Repository: incubator-johnzon Updated Branches: refs/heads/master a1246b944 -> 36816c64b
JOHNZON-84 getting rid of default converters for primitives Project: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/commit/36816c64 Tree: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/tree/36816c64 Diff: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/diff/36816c64 Branch: refs/heads/master Commit: 36816c64b6f3f327b141b35db666b08ebf1b2348 Parents: a1246b9 Author: Romain manni-Bucau <[email protected]> Authored: Fri Jun 3 17:28:22 2016 +0200 Committer: Romain manni-Bucau <[email protected]> Committed: Fri Jun 3 17:28:28 2016 +0200 ---------------------------------------------------------------------- .../jaxrs/ConfigurableJohnzonProvider.java | 4 ++ .../WildcardConfigurableJohnzonProvider.java | 4 ++ .../apache/johnzon/jsonb/JohnzonBuilder.java | 3 ++ .../apache/johnzon/mapper/MapperBuilder.java | 27 ++++++++++++++ .../johnzon/mapper/MappingGeneratorImpl.java | 3 ++ .../johnzon/mapper/MappingParserImpl.java | 39 +++++++++++++++++++- .../org/apache/johnzon/mapper/MapperTest.java | 16 +++++++- 7 files changed, 93 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/36816c64/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java ---------------------------------------------------------------------- diff --git a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java index 7bdb597..dd8b79c 100644 --- a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java +++ b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java @@ -203,4 +203,8 @@ public class ConfigurableJohnzonProvider<T> implements MessageBodyWriter<T>, Mes public void setEnforceQuoteString(final boolean val) { builder.setEnforceQuoteString(val); } + + public void setPrimitiveConverters(final boolean val) { + builder.setPrimitiveConverters(val); + } } http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/36816c64/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java ---------------------------------------------------------------------- diff --git a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java index aa44fec..4df4a7c 100644 --- a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java +++ b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java @@ -211,4 +211,8 @@ public class WildcardConfigurableJohnzonProvider<T> implements MessageBodyWriter public void setEnforceQuoteString(final boolean val) { builder.setEnforceQuoteString(val); } + + public void setPrimitiveConverters(final boolean val) { + builder.setPrimitiveConverters(val); + } } http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/36816c64/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java ---------------------------------------------------------------------- diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java index ea2a937..da23f6a 100644 --- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java +++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java @@ -192,6 +192,9 @@ public class JohnzonBuilder implements JsonbBuilder { config.getProperty("johnzon.enforceQuoteString") .map(v -> !Boolean.class.isInstance(v) ? Boolean.parseBoolean(v.toString()) : Boolean.class.cast(v)) .ifPresent(builder::setEnforceQuoteString); + config.getProperty("johnzon.primitiveConverters") + .map(v -> !Boolean.class.isInstance(v) ? Boolean.parseBoolean(v.toString()) : Boolean.class.cast(v)) + .ifPresent(builder::setPrimitiveConverters); final Map<AdapterKey, Adapter<?, ?>> defaultConverters = createJava8Converters(builder); http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/36816c64/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java index 9091698..944ed9b 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java @@ -80,6 +80,7 @@ public class MapperBuilder { DEFAULT_CONVERTERS.put(new AdapterKey(String.class, String.class), new ConverterAdapter<String>(new StringConverter())); DEFAULT_CONVERTERS.put(new AdapterKey(BigDecimal.class, String.class), new ConverterAdapter<BigDecimal>(new BigDecimalConverter())); DEFAULT_CONVERTERS.put(new AdapterKey(BigInteger.class, String.class), new ConverterAdapter<BigInteger>(new BigIntegerConverter())); + /* primitives should be hanlded low level and adapters will wrap them in string which is unlikely DEFAULT_CONVERTERS.put(new AdapterKey(Byte.class, String.class), new ConverterAdapter<Byte>(new CachedDelegateConverter<Byte>(new ByteConverter()))); DEFAULT_CONVERTERS.put(new AdapterKey(Character.class, String.class), new ConverterAdapter<Character>(new CharacterConverter())); DEFAULT_CONVERTERS.put(new AdapterKey(Double.class, String.class), new ConverterAdapter<Double>(new DoubleConverter())); @@ -96,6 +97,7 @@ public class MapperBuilder { DEFAULT_CONVERTERS.put(new AdapterKey(long.class, String.class), DEFAULT_CONVERTERS.get(new AdapterKey(Long.class, String.class))); DEFAULT_CONVERTERS.put(new AdapterKey(short.class, String.class), DEFAULT_CONVERTERS.get(new AdapterKey(Short.class, String.class))); DEFAULT_CONVERTERS.put(new AdapterKey(boolean.class, String.class), DEFAULT_CONVERTERS.get(new AdapterKey(Boolean.class, String.class))); + */ DEFAULT_CONVERTERS.put(new AdapterKey(Locale.class, String.class), new LocaleConverter()); } @@ -126,6 +128,7 @@ public class MapperBuilder { private Map<Class<?>, ObjectConverter.Reader<?>> objectConverterReaders = new HashMap<Class<?>, ObjectConverter.Reader<?>>(); private Map<Class<?>, ObjectConverter.Writer<?>> objectConverterWriters = new HashMap<Class<?>, ObjectConverter.Writer<?>>(); private Map<Class<?>, String[]> ignoredForFields = new HashMap<Class<?>, String[]>(); + private boolean primitiveConverters; public Mapper build() { if (readerFactory == null || generatorFactory == null) { @@ -186,6 +189,25 @@ public class MapperBuilder { } } + if (primitiveConverters) { + adapters.put(new AdapterKey(Byte.class, String.class), new ConverterAdapter<Byte>(new CachedDelegateConverter<Byte>(new ByteConverter()))); + adapters.put(new AdapterKey(Character.class, String.class), new ConverterAdapter<Character>(new CharacterConverter())); + adapters.put(new AdapterKey(Double.class, String.class), new ConverterAdapter<Double>(new DoubleConverter())); + adapters.put(new AdapterKey(Float.class, String.class), new ConverterAdapter<Float>(new FloatConverter())); + adapters.put(new AdapterKey(Integer.class, String.class), new ConverterAdapter<Integer>(new IntegerConverter())); + adapters.put(new AdapterKey(Long.class, String.class), new ConverterAdapter<Long>(new LongConverter())); + adapters.put(new AdapterKey(Short.class, String.class), new ConverterAdapter<Short>(new ShortConverter())); + adapters.put(new AdapterKey(Boolean.class, String.class), new ConverterAdapter<Boolean>(new CachedDelegateConverter<Boolean>(new BooleanConverter()))); + adapters.put(new AdapterKey(byte.class, String.class), adapters.get(new AdapterKey(Byte.class, String.class))); + adapters.put(new AdapterKey(char.class, String.class), adapters.get(new AdapterKey(Character.class, String.class))); + adapters.put(new AdapterKey(double.class, String.class), adapters.get(new AdapterKey(Double.class, String.class))); + adapters.put(new AdapterKey(float.class, String.class), adapters.get(new AdapterKey(Float.class, String.class))); + adapters.put(new AdapterKey(int.class, String.class), adapters.get(new AdapterKey(Integer.class, String.class))); + adapters.put(new AdapterKey(long.class, String.class), adapters.get(new AdapterKey(Long.class, String.class))); + adapters.put(new AdapterKey(short.class, String.class), adapters.get(new AdapterKey(Short.class, String.class))); + adapters.put(new AdapterKey(boolean.class, String.class), adapters.get(new AdapterKey(Boolean.class, String.class))); + } + return new Mapper( readerFactory, generatorFactory, new MapperConfig( @@ -362,4 +384,9 @@ public class MapperBuilder { this.enforceQuoteString = val; return this; } + + public MapperBuilder setPrimitiveConverters(final boolean val) { + this.primitiveConverters = val; + return this; + } } http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/36816c64/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java index 3ed0655..a88ab83 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java @@ -339,6 +339,9 @@ public class MappingGeneratorImpl implements MappingGenerator { return; } } + if (writePrimitives(key, type, value)) { + return; + } generator.writeStartObject(key); doWriteObjectBody(value); generator.writeEnd(); http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/36816c64/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java index 7a9fcb2..b5a7fab 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java @@ -21,6 +21,7 @@ package org.apache.johnzon.mapper; import org.apache.johnzon.core.JsonLongImpl; import org.apache.johnzon.core.JsonReaderImpl; import org.apache.johnzon.mapper.access.AccessMode; +import org.apache.johnzon.mapper.converter.CharacterConverter; import org.apache.johnzon.mapper.converter.EnumConverter; import org.apache.johnzon.mapper.internal.AdapterKey; import org.apache.johnzon.mapper.internal.ConverterAdapter; @@ -35,6 +36,9 @@ import javax.json.JsonStructure; import javax.json.JsonValue; import javax.xml.bind.DatatypeConverter; import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.math.BigDecimal; @@ -73,9 +77,10 @@ public class MappingParserImpl implements MappingParser { private static final Adapter<Object, String> FALLBACK_CONVERTER = new ConverterAdapter<Object>(new FallbackConverter()); private static final JohnzonParameterizedType ANY_LIST = new JohnzonParameterizedType(List.class, Object.class); - + private static final CharacterConverter CHARACTER_CONVERTER = new CharacterConverter(); // this one is particular, share the logic protected final ConcurrentMap<Adapter<?, ?>, AdapterKey> reverseAdaptersRegistry; + protected final ConcurrentMap<Class<?>, Method> valueOfs = new ConcurrentHashMap<Class<?>, Method>(); private final MapperConfig config; private final Mappings mappings; @@ -572,6 +577,38 @@ public class MappingParserImpl implements MappingParser { return text; } final Adapter converter = findAdapter(aClass); + Method method = valueOfs.get(aClass); + if (method == null && Class.class.isInstance(aClass)) { // handle primitives + final Class cast = Class.class.cast(aClass); + try { + method = cast.getMethod("valueOf", String.class); + if (Modifier.isPublic(method.getModifiers()) && Modifier.isStatic(method.getModifiers())) { + valueOfs.putIfAbsent(cast, method); + } else { + method = null; + } + } catch (final NoSuchMethodException e) { + // if a real primitive (very unlikely) try the wrapper + if (char.class == aClass) { + return CHARACTER_CONVERTER.fromString(text); + } + try { + return convertTo(Class.class.cast(cast.getField("TYPE").get(null)), text); + } catch (final Exception e1) { + // no-op + } + // no-op + } + } + if (method != null) { + try { + return method.invoke(null, text); + } catch (final IllegalAccessException e) { + throw new IllegalStateException(e); + } catch (final InvocationTargetException e) { + throw new MapperException(e.getCause()); + } + } if (converter == null) { config.getAdapters().putIfAbsent(new AdapterKey(String.class, aClass), FALLBACK_CONVERTER); return FALLBACK_CONVERTER.to(text); http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/36816c64/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java index 7967060..88466e3 100644 --- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java +++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java @@ -191,7 +191,8 @@ public class MapperTest { put("a", "val"); put("b", true); put("c", 1); - }}, simpleMapper.readObject(new ByteArrayInputStream("{\"a\":\"val\", \"b\": true, \"c\": 1}".getBytes()), Object.class)); + put("d", true); + }}, simpleMapper.readObject(new ByteArrayInputStream("{\"a\":\"val\", \"b\": true, \"c\": 1, \"d\": true}".getBytes()), Object.class)); // write assertEquals("true", simpleMapper.writeObjectAsString(true)); @@ -199,12 +200,20 @@ public class MapperTest { assertEquals("1", simpleMapper.writeObjectAsString(1)); assertEquals("\"val\"", enforcedQuotes.writeObjectAsString("val")); assertEquals("[\"val1\",\"val2\"]", simpleMapper.writeObjectAsString(asList("val1", "val2"))); - assertEquals("{\"a\":\"val\",\"b\":true,\"c\":1}", simpleMapper.writeObjectAsString(new TreeMap<String, Object>() {{ + assertEquals("{\"a\":\"val\",\"b\":true,\"c\":1,\"d\":true}", simpleMapper.writeObjectAsString(new TreeMap<String, Object>() {{ put("a", "val"); put("b", true); put("c", 1); + put("d", true); }})); } + { // in model + PrimitiveObject p = new PrimitiveObject(); + p.bool = true; + final Mapper fieldMapper = new MapperBuilder().setAccessModeName("field").build(); + assertEquals("{\"bool\":true}", fieldMapper.writeObjectAsString(p)); + assertEquals(Boolean.TRUE, PrimitiveObject.class.cast(fieldMapper.readObject(new StringReader("{\"bool\":true}"), PrimitiveObject.class)).bool); + } } private void assertOneDimension(final Map<String, Object> data, final int size) { @@ -1060,4 +1069,7 @@ public class MapperTest { } } + public static class PrimitiveObject { + public Object bool; + } }
