JOHNZON-39 constructor instantiation using @ConstructorProperties
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 3997ca3..8235853 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
@@ -100,6 +100,10 @@
         instance().writeTo(t, rawType, genericType, annotations, mediaType, httpHeaders, entityStream);
     }
 
+    public void setSupportConstructors(final boolean supportConstructors) {
+        builder.setSupportConstructors(supportConstructors);
+    }
+
     public void setPretty(final boolean pretty) {
         builder.setPretty(pretty);
     }
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonConverter.java
index 1c1a01d..b3691cc 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonConverter.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonConverter.java
@@ -21,10 +21,12 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
+import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
-@Target(METHOD)
+@Target({ METHOD, FIELD, PARAMETER })
 @Retention(RUNTIME)
 public @interface JohnzonConverter {
     Class<? extends Converter<?>> value();
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
index 7a70575..05f76c6 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
@@ -84,13 +84,14 @@
     public Mapper(final JsonReaderFactory readerFactory, final JsonGeneratorFactory generatorFactory,
                   final boolean doClose, final Map<Class<?>, Converter<?>> converters,
                   final int version, final Comparator<String> attributeOrder, final boolean skipNull, final boolean skipEmptyArray,
-                  final AccessMode accessMode, final boolean hiddenConstructorSupported, final boolean treatByteArrayAsBase64) {
+                  final AccessMode accessMode, final boolean hiddenConstructorSupported, final boolean useConstructors,
+                  final boolean treatByteArrayAsBase64) {
         this.readerFactory = readerFactory;
         this.generatorFactory = generatorFactory;
         this.close = doClose;
         this.converters = new ConcurrentHashMap<Type, Converter<?>>(converters);
         this.version = version;
-        this.mappings = new Mappings(attributeOrder, accessMode, hiddenConstructorSupported);
+        this.mappings = new Mappings(attributeOrder, accessMode, hiddenConstructorSupported, useConstructors);
         this.skipNull = skipNull;
         this.skipEmptyArray = skipEmptyArray;
         this.treatByteArrayAsBase64 = treatByteArrayAsBase64;
@@ -587,15 +588,13 @@
             throw new IllegalArgumentException(classMapping.clazz.getName() + " can't be instantiated by Johnzon, this is a write only class");
         }
 
-        final Object t = classMapping.constructor.newInstance();
+        final Object t = !classMapping.constructorHasArguments ?
+                classMapping.constructor.newInstance() : classMapping.constructor.newInstance(createParameters(classMapping, object));
         for (final Map.Entry<String, Mappings.Setter> setter : classMapping.setters.entrySet()) {
             final JsonValue jsonValue = object.get(setter.getKey());
             final Mappings.Setter value = setter.getValue();
             final AccessMode.Writer setterMethod = value.writer;
-            final Object convertedValue = value.converter == null ?
-                    toObject(jsonValue, value.paramType) : jsonValue.getValueType() == ValueType.STRING ?
-                    value.converter.fromString(JsonString.class.cast(jsonValue).getString()) :
-                    value.converter.fromString(jsonValue.toString());
+            final Object convertedValue = toValue(jsonValue, value.converter, value.paramType);
 
             if (convertedValue != null) {
                 setterMethod.write(t, convertedValue);
@@ -605,6 +604,21 @@
         return t;
     }
 
+    private Object toValue(final JsonValue jsonValue, final Converter<?> converter, final Type type) throws Exception {
+        return converter == null ?
+                toObject(jsonValue, type) : jsonValue.getValueType() == ValueType.STRING ?
+                converter.fromString(JsonString.class.cast(jsonValue).getString()) :
+                converter.fromString(jsonValue.toString());
+    }
+
+    private Object[] createParameters(final Mappings.ClassMapping mapping, final JsonObject object) throws Exception {
+        final Object[] objects = new Object[mapping.constructorParameters.length];
+        for (int i = 0; i < mapping.constructorParameters.length; i++) {
+            objects[i] = toValue(object.get(mapping.constructorParameters[i]), mapping.constructorParameterConverters[i], mapping.constructorParameterTypes[i]);
+        }
+        return objects;
+    }
+
     private Object toObject(final JsonValue jsonValue, final Type type) throws Exception {
         if (jsonValue == null || jsonValue == JsonValue.NULL) {
             return null;
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 d46217a..5802ae8 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
@@ -94,6 +94,7 @@
     private AccessMode accessMode = new MethodAccessMode(false);
     private boolean treatByteArrayAsBase64;
     private final Map<Class<?>, Converter<?>> converters = new HashMap<Class<?>, Converter<?>>(DEFAULT_CONVERTERS);
+    private boolean supportConstructors;
 
     public Mapper build() {
         if (readerFactory == null || generatorFactory == null) {
@@ -134,6 +135,7 @@
                 skipNull, skipEmptyArray,
                 accessMode,
                 supportHiddenAccess,
+                supportConstructors,
                 treatByteArrayAsBase64);
     }
 
@@ -240,4 +242,8 @@
         return this;
     }
 
+    public MapperBuilder setSupportConstructors(final boolean supportConstructors) {
+        this.supportConstructors = supportConstructors;
+        return this;
+    }
 }
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java
index 19a90d8..6fafcc3 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java
@@ -23,6 +23,8 @@
 import org.apache.johnzon.mapper.JohnzonIgnore;
 import org.apache.johnzon.mapper.access.AccessMode;
 
+import java.beans.ConstructorProperties;
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.ParameterizedType;
@@ -47,25 +49,65 @@
         public final Map<String, Getter> getters;
         public final Map<String, Setter> setters;
         public final Constructor<?> constructor;
+        public final boolean constructorHasArguments;
+        public final String[] constructorParameters;
+        public final Converter<?>[] constructorParameterConverters;
+        public final Type[] constructorParameterTypes;
 
         protected ClassMapping(final Class<?> clazz,
                                final Map<String, Getter> getters, final Map<String, Setter> setters,
-                               final boolean acceptHiddenConstructor) {
+                               final boolean acceptHiddenConstructor, final boolean useConstructor) {
             this.clazz = clazz;
             this.getters = getters;
             this.setters = setters;
-            this.constructor = findConstructor(acceptHiddenConstructor);
+            this.constructor = findConstructor(acceptHiddenConstructor, useConstructor);
+
+            this.constructorHasArguments = this.constructor.getGenericParameterTypes().length > 0;
+            if (this.constructorHasArguments) {
+                this.constructorParameterTypes = this.constructor.getGenericParameterTypes();
+
+                this.constructorParameters = new String[this.constructor.getGenericParameterTypes().length];
+                final ConstructorProperties constructorProperties = this.constructor.getAnnotation(ConstructorProperties.class);
+                System.arraycopy(constructorProperties.value(), 0, this.constructorParameters, 0, this.constructorParameters.length);
+
+                this.constructorParameterConverters = new Converter<?>[this.constructor.getGenericParameterTypes().length];
+                for (int i = 0; i < this.constructorParameters.length; i++) {
+                    for (final Annotation a : this.constructor.getParameterAnnotations()[i]) {
+                        if (a.annotationType() == JohnzonConverter.class) {
+                            try {
+                                this.constructorParameterConverters[i] = JohnzonConverter.class.cast(a).value().newInstance();
+                            } catch (final Exception e) {
+                                throw new IllegalArgumentException(e);
+                            }
+                        }
+                    }
+                }
+            } else {
+                this.constructorParameterTypes = null;
+                this.constructorParameters = null;
+                this.constructorParameterConverters = null;
+            }
         }
 
-        private Constructor<?> findConstructor(final boolean acceptHiddenConstructor) {
+        private Constructor<?> findConstructor(final boolean acceptHiddenConstructor, final boolean useConstructor) {
+            Constructor<?> found = null;
             for (final Constructor<?> c : clazz.getDeclaredConstructors()) {
                 if (c.getParameterTypes().length == 0) {
                     if (!Modifier.isPublic(c.getModifiers()) && acceptHiddenConstructor) {
                         c.setAccessible(true);
                     }
-                    return c;
+                    found = c;
+                    if (!useConstructor) {
+                        break;
+                    }
+                } else if (c.getAnnotation(ConstructorProperties.class) != null) {
+                    found = c;
+                    break;
                 }
             }
+            if (found != null) {
+                return found;
+            }
             try {
                 return clazz.getConstructor();
             } catch (final NoSuchMethodException e) {
@@ -129,12 +171,15 @@
     protected final ConcurrentMap<Type, CollectionMapping> collections = new ConcurrentHashMap<Type, CollectionMapping>();
     protected final Comparator<String> fieldOrdering;
     private final boolean supportHiddenConstructors;
+    private final boolean supportConstructors;
     private final AccessMode accessMode;
 
-    public Mappings(final Comparator<String> attributeOrder, final AccessMode accessMode, final boolean supportHiddenConstructors) {
+    public Mappings(final Comparator<String> attributeOrder, final AccessMode accessMode,
+                    final boolean supportHiddenConstructors, final boolean supportConstructors) {
         this.fieldOrdering = attributeOrder;
         this.accessMode = accessMode;
         this.supportHiddenConstructors = supportHiddenConstructors;
+        this.supportConstructors = supportConstructors;
     }
 
     public <T> CollectionMapping findCollectionMapping(final ParameterizedType genericType) {
@@ -258,7 +303,7 @@
                 setters.put(key, new Setter(value, isPrimitive(param), param, findConverter(value), writeIgnore != null ? writeIgnore.minVersion() : -1));
             }
         }
-        return new ClassMapping(clazz, getters, setters, supportHiddenConstructors);
+        return new ClassMapping(clazz, getters, setters, supportHiddenConstructors, supportConstructors);
     }
 
     private static Converter findConverter(final AccessMode.DecoratedType method) {
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 49b9954..4415c53 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
@@ -22,6 +22,7 @@
 import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType;
 import org.junit.Test;
 
+import java.beans.ConstructorProperties;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.StringReader;
@@ -438,6 +439,18 @@
         assertEquals(asList("a", "b"), value.getTheCollection());
     }
 
+
+    @Test
+    public void constructor() {
+        final ConstructorUsage value = new MapperBuilder().setSupportConstructors(true).build()
+                .readObject(
+                    new ByteArrayInputStream(
+                        "{\"converted\":\"yeah\",\"value\":\"test\",\"collection\":[\"a\",\"b\"]}".getBytes()),
+                        ConstructorUsage.class);
+        assertEquals("test", value.aValue);
+        assertEquals(asList("a", "b"), value.theCollection);
+    }
+
     @Test
     public void aliases() {
         {
@@ -821,6 +834,31 @@
             return theCollection;
         }
     }
+
+    public static class ConstructorUsage {
+        private final String foo;
+        private final String aValue;
+        private final Collection<String> theCollection;
+
+        @ConstructorProperties({ "value", "collection", "converted" })
+        public ConstructorUsage(final String aValue, final Collection<String> theCollection, @JohnzonConverter(YeahConverter.class) final String foo) {
+            this.aValue = aValue;
+            this.foo = foo;
+            this.theCollection = theCollection;
+        }
+
+        public static class YeahConverter implements Converter<String> {
+            @Override
+            public String toString(final String instance) {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public String fromString(final String text) {
+                return "yeah";
+            }
+        }
+    }
     
     /*public static class ByteArray {