Skip to content

Commit

Permalink
First version of @convert(with=SomeConverter.class)
Browse files Browse the repository at this point in the history
  • Loading branch information
chkal committed Sep 2, 2012
1 parent cc0262a commit 3c60b6d
Show file tree
Hide file tree
Showing 10 changed files with 364 additions and 0 deletions.
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 Convert
{
Class<?> with();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* 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.Convert;
import org.ocpsoft.rewrite.annotation.api.FieldContext;
import org.ocpsoft.rewrite.annotation.api.HandlerChain;
import org.ocpsoft.rewrite.annotation.spi.ConverterProvider;
import org.ocpsoft.rewrite.annotation.spi.FieldAnnotationHandler;
import org.ocpsoft.rewrite.bind.BindingBuilder;
import org.ocpsoft.rewrite.bind.Converter;
import org.ocpsoft.rewrite.context.EvaluationContext;
import org.ocpsoft.rewrite.event.Rewrite;

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

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

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

@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public void process(FieldContext context, Convert 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 converter
Class<?> converterType = annotation.with();
LazyConverterAdapter converter = new LazyConverterAdapter(converterType);
bindingBuilder.convertedBy(converter);

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

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

}

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

private final Class<?> converterClass;

public LazyConverterAdapter(Class<?> clazz)
{
this.converterClass = clazz;
}

@Override
@SuppressWarnings("unchecked")
public Object convert(Rewrite event, EvaluationContext context, Object value)
{

Converter<?> converter = null;

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

return converter.convert(event, context, value);

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* 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.Converter;

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

/**
* Create a Rewrite {@link Converter} from the given converter class. Which types are supported is up to the
* implementation class. A JSF implementation would for example support JSF converters.
*/
Converter<?> getByType(Class<?> converterClass);
}
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.Converter;

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

@Override
public Converter<?> getByType(Class<?> converterClass)
{

if (Converter.class.isAssignableFrom(converterClass)) {

try {
return (Converter<?>) converterClass.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
Expand Up @@ -8,3 +8,4 @@ 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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.ocpsoft.rewrite.annotation.spi.DefaultConverterProvider
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.ocpsoft.rewrite.annotation.convert;

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

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

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

@ParameterBinding
@Convert(with = LowercaseConverter.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,42 @@
package org.ocpsoft.rewrite.annotation.convert;

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 CustomConverterTest extends RewriteTestBase
{

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

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

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

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

public class LowercaseConverter implements Converter<String>
{

@Override
public String convert(Rewrite event, EvaluationContext context, Object value)
{
return value.toString().toLowerCase();
}

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

import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.math.BigDecimal;

import org.junit.Test;
import org.ocpsoft.rewrite.bind.Converter;
import org.ocpsoft.rewrite.context.EvaluationContext;
import org.ocpsoft.rewrite.event.Rewrite;

public class DefaultConverterProviderTest
{

@Test
public void testCreateRewriteConverter()
{
Converter<?> converter = new DefaultConverterProvider().getByType(TestConverter.class);
assertNotNull(converter);
assertTrue(converter instanceof TestConverter);
}

@Test
public void testUnsupportedType()
{
Converter<?> converter = new DefaultConverterProvider().getByType(BigDecimal.class);
assertNull(converter);
}

public static class TestConverter implements Converter<Object>
{
@Override
public Object convert(Rewrite event, EvaluationContext context, Object value)
{
return null;
}
}

}

0 comments on commit 3c60b6d

Please sign in to comment.