From 47552bdb0673a88b0cd76cebc40f65477edd58d0 Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Thu, 20 Apr 2017 08:28:46 +0200 Subject: [PATCH 1/4] WW-4210 Extends annotation to allow use class instead of string --- .../conversion/annotations/TypeConversion.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/annotations/TypeConversion.java b/core/src/main/java/com/opensymphony/xwork2/conversion/annotations/TypeConversion.java index 6640659a0..db57573e2 100644 --- a/core/src/main/java/com/opensymphony/xwork2/conversion/annotations/TypeConversion.java +++ b/core/src/main/java/com/opensymphony/xwork2/conversion/annotations/TypeConversion.java @@ -15,6 +15,8 @@ */ package com.opensymphony.xwork2.conversion.annotations; +import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -175,9 +177,20 @@ public @interface TypeConversion { * Note: This can not be used with ConversionRule.KEY_PROPERTY! * * @return class of the TypeConverter to be used as converter + * @deprecated user {@link #converterClass()} instead */ + @Deprecated String converter() default ""; + /** + * The class of the TypeConverter to be used as converter. + * + * Note: This can not be used with ConversionRule.KEY_PROPERTY! + * + * @return class of the TypeConverter to be used as converter + */ + Class converterClass() default XWorkBasicConverter.class; + /** * If used with ConversionRule.KEY_PROPERTY specify a value here! * From 3e76564d3ce8d5b4a3938efd3a76c521eb045f38 Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Thu, 20 Apr 2017 08:29:24 +0200 Subject: [PATCH 2/4] WW-4210 Supports defining converter as a class in the annotation --- .../conversion/TypeConverterCreator.java | 9 +++++ .../DefaultConversionAnnotationProcessor.java | 36 ++++++++++++++----- .../impl/DefaultTypeConverterCreator.java | 10 +++++- .../conversion/impl/XWorkConverter.java | 4 +-- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/TypeConverterCreator.java b/core/src/main/java/com/opensymphony/xwork2/conversion/TypeConverterCreator.java index 738bbe82f..438d31ca6 100644 --- a/core/src/main/java/com/opensymphony/xwork2/conversion/TypeConverterCreator.java +++ b/core/src/main/java/com/opensymphony/xwork2/conversion/TypeConverterCreator.java @@ -14,4 +14,13 @@ public interface TypeConverterCreator { */ TypeConverter createTypeConverter(String className) throws Exception; + /** + * Creates {@link TypeConverter} from given class + * + * @param clazz convert class + * @return instance of {@link TypeConverter} + * @throws Exception when cannot create/cast to {@link TypeConverter} + */ + TypeConverter createTypeConverter(Class clazz) throws Exception; + } diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultConversionAnnotationProcessor.java b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultConversionAnnotationProcessor.java index c3faae3a5..5396712b2 100644 --- a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultConversionAnnotationProcessor.java +++ b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultConversionAnnotationProcessor.java @@ -8,6 +8,7 @@ import com.opensymphony.xwork2.conversion.annotations.ConversionRule; import com.opensymphony.xwork2.conversion.annotations.ConversionType; import com.opensymphony.xwork2.conversion.annotations.TypeConversion; import com.opensymphony.xwork2.inject.Inject; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -34,28 +35,43 @@ public class DefaultConversionAnnotationProcessor implements ConversionAnnotatio } public void process(Map mapping, TypeConversion tc, String key) { - LOG.debug("TypeConversion [{}] with key: [{}]", tc.converter(), key); + LOG.debug("TypeConversion [{}/{}] with key: [{}]", tc.converter(), tc.converterClass(), key); if (key == null) { return; } try { if (tc.type() == ConversionType.APPLICATION) { - converterHolder.addDefaultMapping(key, converterCreator.createTypeConverter(tc.converter())); + if (StringUtils.isNoneEmpty(tc.converter())) { + converterHolder.addDefaultMapping(key, converterCreator.createTypeConverter(tc.converter())); + } else { + converterHolder.addDefaultMapping(key, converterCreator.createTypeConverter(tc.converterClass())); + } } else { if (tc.rule() == ConversionRule.KEY_PROPERTY || tc.rule() == ConversionRule.CREATE_IF_NULL) { mapping.put(key, tc.value()); } //for properties of classes else if (tc.rule() != ConversionRule.ELEMENT || tc.rule() == ConversionRule.KEY || tc.rule() == ConversionRule.COLLECTION) { - mapping.put(key, converterCreator.createTypeConverter(tc.converter())); + if (StringUtils.isNoneEmpty(tc.converter())) { + mapping.put(key, converterCreator.createTypeConverter(tc.converter())); + } else { + mapping.put(key, converterCreator.createTypeConverter(tc.converterClass())); + } } //for keys of Maps else if (tc.rule() == ConversionRule.KEY) { - Class converterClass = Thread.currentThread().getContextClassLoader().loadClass(tc.converter()); + Class converterClass; + if (StringUtils.isNoneEmpty(tc.converter())) { + converterClass = Thread.currentThread().getContextClassLoader().loadClass(tc.converter()); + //check if the converter is a type converter if it is one + //then just put it in the map as is. Otherwise + //put a value in for the type converter of the class + } else { + converterClass = tc.converterClass(); + } + LOG.debug("Converter class: [{}]", converterClass); - //check if the converter is a type converter if it is one - //then just put it in the map as is. Otherwise - //put a value in for the type converter of the class + if (converterClass.isAssignableFrom(TypeConverter.class)) { mapping.put(key, converterCreator.createTypeConverter(tc.converter())); } else { @@ -65,7 +81,11 @@ public class DefaultConversionAnnotationProcessor implements ConversionAnnotatio } //elements(values) of maps / lists else { - mapping.put(key, Thread.currentThread().getContextClassLoader().loadClass(tc.converter())); + if (StringUtils.isNoneEmpty(tc.converter())) { + mapping.put(key, Thread.currentThread().getContextClassLoader().loadClass(tc.converter())); + } else { + mapping.put(key, tc.converterClass()); + } } } } catch (Exception e) { diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultTypeConverterCreator.java b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultTypeConverterCreator.java index ed6ac2265..d9613b25a 100644 --- a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultTypeConverterCreator.java +++ b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultTypeConverterCreator.java @@ -19,8 +19,16 @@ public class DefaultTypeConverterCreator implements TypeConverterCreator { } public TypeConverter createTypeConverter(String className) throws Exception { - // type converters are used across users Object obj = objectFactory.buildBean(className, null); + return getTypeConverter(obj); + } + + public TypeConverter createTypeConverter(Class clazz) throws Exception { + Object obj = objectFactory.buildBean(clazz, null); + return getTypeConverter(obj); + } + + protected TypeConverter getTypeConverter(Object obj) { if (obj instanceof TypeConverter) { return (TypeConverter) obj; diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkConverter.java b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkConverter.java index 4257411e8..0d556139b 100644 --- a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkConverter.java +++ b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkConverter.java @@ -487,9 +487,9 @@ public class XWorkConverter extends DefaultTypeConverter { } if (LOG.isDebugEnabled()) { if (StringUtils.isEmpty(tc.key())) { - LOG.debug("WARNING! key of @TypeConversion [{}] applied to [{}] is empty!", tc.converter(), clazz.getName()); + LOG.debug("WARNING! key of @TypeConversion [{}/{}] applied to [{}] is empty!", tc.converter(), tc.converterClass(), clazz.getName()); } else { - LOG.debug("TypeConversion [{}] with key: [{}]", tc.converter(), tc.key()); + LOG.debug("TypeConversion [{}/{}] with key: [{}]", tc.converter(), tc.converterClass(), tc.key()); } } annotationProcessor.process(mapping, tc, tc.key()); From ec2412492503cdd0e90abf7f2cf2c3e50c8fa70c Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Thu, 20 Apr 2017 08:29:53 +0200 Subject: [PATCH 3/4] WW-4210 Updates tests to use the class definition instead of string --- .../xwork2/conversion/ConversionTestAction.java | 9 +++++---- .../opensymphony/xwork2/test/AnnotationDataAware.java | 6 ++---- .../opensymphony/xwork2/test/AnnotationTestBean2.java | 5 ++--- .../com/opensymphony/xwork2/test/AnnotationUser.java | 4 ++-- .../xwork2/test/annotations/PersonAction.java | 4 ++-- .../java/com/opensymphony/xwork2/util/AnnotatedCat.java | 4 +--- 6 files changed, 14 insertions(+), 18 deletions(-) diff --git a/core/src/test/java/com/opensymphony/xwork2/conversion/ConversionTestAction.java b/core/src/test/java/com/opensymphony/xwork2/conversion/ConversionTestAction.java index de743fe39..d19aaf18f 100644 --- a/core/src/test/java/com/opensymphony/xwork2/conversion/ConversionTestAction.java +++ b/core/src/test/java/com/opensymphony/xwork2/conversion/ConversionTestAction.java @@ -21,6 +21,7 @@ import com.opensymphony.xwork2.conversion.annotations.ConversionRule; import com.opensymphony.xwork2.conversion.annotations.ConversionType; import com.opensymphony.xwork2.conversion.annotations.TypeConversion; +import java.math.BigInteger; import java.util.HashMap; import java.util.List; @@ -49,7 +50,7 @@ public class ConversionTestAction implements Action { return convertInt; } - @TypeConversion(type = ConversionType.APPLICATION, converter = "com.opensymphony.xwork2.util.XWorkBasicConverter") + @TypeConversion(type = ConversionType.APPLICATION) public void setConvertInt( String convertInt ) { this.convertInt = convertInt; } @@ -67,7 +68,7 @@ public class ConversionTestAction implements Action { return users; } - @TypeConversion(rule = ConversionRule.COLLECTION, converter = "java.lang.String") + @TypeConversion(rule = ConversionRule.COLLECTION, converterClass = String.class) public void setUsers( List users ) { this.users = users; } @@ -76,7 +77,7 @@ public class ConversionTestAction implements Action { return keyValues; } - @TypeConversion(rule = ConversionRule.MAP, converter = "java.math.BigInteger") + @TypeConversion(rule = ConversionRule.MAP, converterClass = BigInteger.class) public void setKeyValues( HashMap keyValues ) { this.keyValues = keyValues; } @@ -90,7 +91,7 @@ public class ConversionTestAction implements Action { * Application level exceptions should be handled by returning * an error value, such as Action.ERROR. */ - @TypeConversion(type = ConversionType.APPLICATION, key = "java.util.Date", converter = "com.opensymphony.xwork2.util.XWorkBasicConverter") + @TypeConversion(type = ConversionType.APPLICATION, key = "java.util.Date") public String execute() throws Exception { return SUCCESS; } diff --git a/core/src/test/java/com/opensymphony/xwork2/test/AnnotationDataAware.java b/core/src/test/java/com/opensymphony/xwork2/test/AnnotationDataAware.java index fd63584f7..a30497bfe 100644 --- a/core/src/test/java/com/opensymphony/xwork2/test/AnnotationDataAware.java +++ b/core/src/test/java/com/opensymphony/xwork2/test/AnnotationDataAware.java @@ -17,6 +17,7 @@ package com.opensymphony.xwork2.test; import com.opensymphony.xwork2.conversion.annotations.Conversion; import com.opensymphony.xwork2.conversion.annotations.TypeConversion; +import com.opensymphony.xwork2.conversion.impl.FooBarConverter; import com.opensymphony.xwork2.util.Bar; import com.opensymphony.xwork2.validator.annotations.RequiredFieldValidator; import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator; @@ -29,15 +30,12 @@ import com.opensymphony.xwork2.validator.annotations.Validation; * @author Mark Woon * @author Rainer Hermanns */ -@Validation() @Conversion() public interface AnnotationDataAware { void setBarObj(Bar b); - @TypeConversion( - converter = "com.opensymphony.xwork2.conversion.impl.FooBarConverter" - ) + @TypeConversion(converterClass = FooBarConverter.class) Bar getBarObj(); @RequiredFieldValidator(message = "You must enter a value for data.") diff --git a/core/src/test/java/com/opensymphony/xwork2/test/AnnotationTestBean2.java b/core/src/test/java/com/opensymphony/xwork2/test/AnnotationTestBean2.java index 3a1396b9e..ccd5ec1b9 100644 --- a/core/src/test/java/com/opensymphony/xwork2/test/AnnotationTestBean2.java +++ b/core/src/test/java/com/opensymphony/xwork2/test/AnnotationTestBean2.java @@ -18,6 +18,7 @@ package com.opensymphony.xwork2.test; import com.opensymphony.xwork2.AnnotatedTestBean; import com.opensymphony.xwork2.conversion.annotations.Conversion; import com.opensymphony.xwork2.conversion.annotations.TypeConversion; +import com.opensymphony.xwork2.conversion.impl.FooBarConverter; import com.opensymphony.xwork2.util.Bar; import com.opensymphony.xwork2.util.Cat; @@ -56,9 +57,7 @@ public class AnnotationTestBean2 extends AnnotatedTestBean implements Annotation return cat; } - @TypeConversion( - key = "cat", converter = "com.opensymphony.xwork2.conversion.impl.FooBarConverter" - ) + @TypeConversion(key = "cat", converterClass = FooBarConverter.class) public void setCat(Cat cat) { this.cat = cat; } diff --git a/core/src/test/java/com/opensymphony/xwork2/test/AnnotationUser.java b/core/src/test/java/com/opensymphony/xwork2/test/AnnotationUser.java index be2f86361..fbf353541 100644 --- a/core/src/test/java/com/opensymphony/xwork2/test/AnnotationUser.java +++ b/core/src/test/java/com/opensymphony/xwork2/test/AnnotationUser.java @@ -82,12 +82,12 @@ public class AnnotationUser implements AnnotationUserMarker { } @KeyProperty( value = "name") - @TypeConversion( converter = "java.lang.String", rule = ConversionRule.COLLECTION) + @TypeConversion(converterClass = String.class, rule = ConversionRule.COLLECTION) public List getList() { return list; } - @TypeConversion( converter = "java.lang.String", rule = ConversionRule.MAP) + @TypeConversion(converterClass = String.class, rule = ConversionRule.MAP) public void setMap(Map m) { map = m; } diff --git a/core/src/test/java/com/opensymphony/xwork2/test/annotations/PersonAction.java b/core/src/test/java/com/opensymphony/xwork2/test/annotations/PersonAction.java index 72e20ef8e..c4a6c403a 100644 --- a/core/src/test/java/com/opensymphony/xwork2/test/annotations/PersonAction.java +++ b/core/src/test/java/com/opensymphony/xwork2/test/annotations/PersonAction.java @@ -11,10 +11,10 @@ import java.util.List; conversions={ @TypeConversion(type=ConversionType.APPLICATION, key="com.opensymphony.xwork2.test.annotations.Address", - converter="com.opensymphony.xwork2.test.annotations.AddressTypeConverter"), + converterClass=AddressTypeConverter.class), @TypeConversion(type=ConversionType.APPLICATION, key="com.opensymphony.xwork2.test.annotations.Person", - converter="com.opensymphony.xwork2.test.annotations.PersonTypeConverter")}) + converterClass=PersonTypeConverter.class)}) public class PersonAction { List users; private List
address; diff --git a/core/src/test/java/com/opensymphony/xwork2/util/AnnotatedCat.java b/core/src/test/java/com/opensymphony/xwork2/util/AnnotatedCat.java index 573315967..fdb0a50de 100644 --- a/core/src/test/java/com/opensymphony/xwork2/util/AnnotatedCat.java +++ b/core/src/test/java/com/opensymphony/xwork2/util/AnnotatedCat.java @@ -50,9 +50,7 @@ public class AnnotatedCat { this.kittens = kittens; } - @TypeConversion( - key = "kittens", converter = "com.opensymphony.xwork2.util.Cat" - ) + @TypeConversion(key = "kittens", converterClass = Cat.class) public List getKittens() { return kittens; } From a58452571c90314f8ed56301133a2a7f7ad1c67b Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Thu, 20 Apr 2017 08:34:55 +0200 Subject: [PATCH 4/4] WW-4210 Updates JavaDocs --- .../conversion/annotations/TypeConversion.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/annotations/TypeConversion.java b/core/src/main/java/com/opensymphony/xwork2/conversion/annotations/TypeConversion.java index db57573e2..609936c6a 100644 --- a/core/src/main/java/com/opensymphony/xwork2/conversion/annotations/TypeConversion.java +++ b/core/src/main/java/com/opensymphony/xwork2/conversion/annotations/TypeConversion.java @@ -79,11 +79,17 @@ import java.lang.annotation.Target; * * * converter - * either this or value + * DEPRECATED: either this or value *   * The class name of the TypeConverter to be used as converter. * * + * converterClass + * either this or value + *   + * The class of the TypeConverter to be used as converter. XWorkBasicConverter by default. + * + * * value * either converter or this *   @@ -108,27 +114,27 @@ import java.lang.annotation.Target; * * private HashMap keyValues = null; * - * @TypeConversion(type = ConversionType.APPLICATION, converter = "com.opensymphony.xwork2.util.XWorkBasicConverter") + * @TypeConversion(type = ConversionType.APPLICATION) * public void setConvertInt( String convertInt ) { * this.convertInt = convertInt; * } * - * @TypeConversion(converter = "com.opensymphony.xwork2.util.XWorkBasicConverter") + * @TypeConversion(converterClass = XWorkBasicConverter.class) * public void setConvertDouble( String convertDouble ) { * this.convertDouble = convertDouble; * } * - * @TypeConversion(rule = ConversionRule.COLLECTION, converter = "java.util.String") + * @TypeConversion(rule = ConversionRule.COLLECTION, converterClass = String.class) * public void setUsers( List users ) { * this.users = users; * } * - * @TypeConversion(rule = ConversionRule.MAP, converter = "java.math.BigInteger") + * @TypeConversion(rule = ConversionRule.MAP, converterClass = BigInteger.class) * public void setKeyValues( HashMap keyValues ) { * this.keyValues = keyValues; * } * - * @TypeConversion(type = ConversionType.APPLICATION, property = "java.util.Date", converter = "com.opensymphony.xwork2.util.XWorkBasicConverter") + * @TypeConversion(type = ConversionType.APPLICATION, property = "java.util.Date", converterClass = XWorkBasicConverter.class) * public String execute() throws Exception { * return SUCCESS; * }