Skip to content

Commit

Permalink
Added support for @Validate to annotations module (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
chkal committed Sep 3, 2012
1 parent 3c60b6d commit 2d65a4b
Show file tree
Hide file tree
Showing 9 changed files with 333 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2011 <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ocpsoft.rewrite.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Inherited
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Validate
{
Class<?> with();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright 2011 <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ocpsoft.rewrite.annotation.handler;

import java.lang.reflect.Field;
import java.util.Iterator;

import org.ocpsoft.common.services.ServiceLoader;
import org.ocpsoft.common.util.Assert;
import org.ocpsoft.logging.Logger;
import org.ocpsoft.rewrite.annotation.Validate;
import org.ocpsoft.rewrite.annotation.api.FieldContext;
import org.ocpsoft.rewrite.annotation.api.HandlerChain;
import org.ocpsoft.rewrite.annotation.spi.FieldAnnotationHandler;
import org.ocpsoft.rewrite.annotation.spi.ValidatorProvider;
import org.ocpsoft.rewrite.bind.BindingBuilder;
import org.ocpsoft.rewrite.bind.Validator;
import org.ocpsoft.rewrite.context.EvaluationContext;
import org.ocpsoft.rewrite.event.Rewrite;

/**
* Handler for {@link Validate}.
*
* @author Christian Kaltepoth
*/
public class ValidateHandler extends FieldAnnotationHandler<Validate>
{
private final Logger log = Logger.getLogger(ValidateHandler.class);

@Override
public Class<Validate> handles()
{
return Validate.class;
}

@Override
public int priority()
{
return HandlerWeights.WEIGHT_TYPE_ENRICHING;
}

@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public void process(FieldContext context, Validate annotation, HandlerChain chain)
{
Field field = context.getJavaField();

// locate the binding previously created by @ParameterBinding
BindingBuilder bindingBuilder = (BindingBuilder) context.get(BindingBuilder.class);
Assert.notNull(bindingBuilder, "No binding found for field: " + field);

// add the validator
Class<?> validatorType = annotation.with();
LazyValidatorAdapter validator = new LazyValidatorAdapter(validatorType);
bindingBuilder.validatedBy(validator);

// some logging
if (log.isTraceEnabled()) {
log.trace("Attached validator adapeter for [{}] to field [{}] of class [{}]", new Object[] {
validatorType.getSimpleName(), field.getName(), field.getDeclaringClass().getName()
});
}

// continue with the chain
chain.proceed();

}

/**
* This class uses the {@link ValidatorProvider} SPI to lazily obtain the {@link Validator} for a given {@link Class}
* instance.
*/
private static class LazyValidatorAdapter implements Validator<Object>
{

private final Class<?> validatorClass;

public LazyValidatorAdapter(Class<?> clazz)
{
this.validatorClass = clazz;
}

@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public boolean validate(Rewrite event, EvaluationContext context, Object value)
{

Validator validator = null;

// let one of the SPI implementations build the validator
Iterator<ValidatorProvider> providers = ServiceLoader.load(ValidatorProvider.class).iterator();
while (providers.hasNext()) {
validator = providers.next().getByType(validatorClass);
if (validator != null) {
break;
}
}
Assert.notNull(validator, "Could not build validator for type: " + validatorClass.getName());

return validator.validate(event, context, value);

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2011 <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ocpsoft.rewrite.annotation.spi;

import org.ocpsoft.rewrite.bind.Validator;

/**
* Default implementation of {@link ValidatorProvider} that builds {@link Validator} instances by creating an instance
* of the supplied class using the default constructor.
*
* @author Christian Kaltepoth
*/
public class DefaultValidatorProvider implements ValidatorProvider
{

@Override
public Validator<?> getByType(Class<?> clazz)
{

if (Validator.class.isAssignableFrom(clazz)) {

try {
return (Validator<?>) clazz.newInstance();
}
catch (InstantiationException e) {
throw new IllegalArgumentException(e);
}
catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
}

}

return null;

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2011 <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ocpsoft.rewrite.annotation.spi;

import org.ocpsoft.rewrite.bind.Validator;

/**
* SPI for providing integration with other validation frameworks. Implementations should be able to build an Rewrite
* {@link Validator} from any kind of 3rd party class.
*
* @author Christian Kaltepoth
*/
public interface ValidatorProvider
{

/**
* Create a Rewrite {@link Validator} from the given validator class. Which types are supported is up to the
* implementation class. A JSF implementation would for example support JSF validator.
*/
Validator<?> getByType(Class<?> validatorClass);

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ org.ocpsoft.rewrite.annotation.handler.RolesRequiredHandler
org.ocpsoft.rewrite.annotation.handler.ParameterBindingHandler
org.ocpsoft.rewrite.annotation.handler.MatchesHandler
org.ocpsoft.rewrite.annotation.handler.ForwardToHandler
org.ocpsoft.rewrite.annotation.handler.ConvertHandler
org.ocpsoft.rewrite.annotation.handler.ConvertHandler
org.ocpsoft.rewrite.annotation.handler.ValidateHandler
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.ocpsoft.rewrite.annotation.spi.DefaultValidatorProvider
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.ocpsoft.rewrite.annotation.validate;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

import org.ocpsoft.rewrite.annotation.Join;
import org.ocpsoft.rewrite.annotation.ParameterBinding;
import org.ocpsoft.rewrite.annotation.Validate;

@Named
@RequestScoped
@Join(path = "/validate/{value}/", to = "/validate.jsp")
public class CustomValidatorBean
{

@ParameterBinding
@Validate(with = EvenLengthValidator.class)
private String value;

public String getValue()
{
return value;
}

public void setValue(String value)
{
this.value = value;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.ocpsoft.rewrite.annotation.validate;

import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;

import org.apache.http.client.methods.HttpGet;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ocpsoft.rewrite.annotation.RewriteAnnotationTest;
import org.ocpsoft.rewrite.test.HttpAction;
import org.ocpsoft.rewrite.test.RewriteTest;
import org.ocpsoft.rewrite.test.RewriteTestBase;

@RunWith(Arquillian.class)
public class CustomValidatorTest extends RewriteTestBase
{

@Deployment(testable = false)
public static WebArchive getDeployment()
{
return RewriteTest.getDeployment()
.addAsLibrary(RewriteAnnotationTest.getRewriteAnnotationArchive())
.addAsLibrary(RewriteAnnotationTest.getRewriteCdiArchive())
.addClasses(CustomValidatorBean.class, EvenLengthValidator.class)
.addAsWebResource(new StringAsset(
"Value: [${customValidatorBean.value}]"),
"validate.jsp");
}

@Test
public void testValidationWithValidValue() throws Exception
{
HttpAction<HttpGet> action = get("/validate/abcd/");
assertEquals(200, action.getStatusCode());
assertTrue(action.getResponseContent().contains("Value: [abcd]"));
}

@Test
public void testValidationWithInvalidValue() throws Exception
{
HttpAction<HttpGet> action = get("/validate/abc/");
assertEquals(404, action.getStatusCode());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.ocpsoft.rewrite.annotation.validate;

import org.ocpsoft.rewrite.bind.Validator;
import org.ocpsoft.rewrite.context.EvaluationContext;
import org.ocpsoft.rewrite.event.Rewrite;

public class EvenLengthValidator implements Validator<String>
{

@Override
public boolean validate(Rewrite event, EvaluationContext context, String value)
{
return value.trim().length() % 2 == 0;
}

}

0 comments on commit 2d65a4b

Please sign in to comment.