Coverage Report - org.apache.johnzon.mapper.Mapper
 
Classes in this File Line Coverage Branch Coverage Complexity
Mapper
80%
280/349
73%
210/286
6,39
Mapper$1
N/A
N/A
6,39
Mapper$FallbackConverter
66%
2/3
N/A
6,39
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements. See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership. The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License. You may obtain a copy of the License at
 9  
  *
 10  
  * http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied. See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.johnzon.mapper;
 20  
 
 21  
 import org.apache.johnzon.mapper.access.AccessMode;
 22  
 import org.apache.johnzon.mapper.converter.EnumConverter;
 23  
 import org.apache.johnzon.mapper.reflection.JohnzonCollectionType;
 24  
 import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType;
 25  
 import org.apache.johnzon.mapper.reflection.Mappings;
 26  
 
 27  
 import javax.json.JsonArray;
 28  
 import javax.json.JsonNumber;
 29  
 import javax.json.JsonObject;
 30  
 import javax.json.JsonReader;
 31  
 import javax.json.JsonReaderFactory;
 32  
 import javax.json.JsonString;
 33  
 import javax.json.JsonValue;
 34  
 import javax.json.JsonValue.ValueType;
 35  
 import javax.json.stream.JsonGenerator;
 36  
 import javax.json.stream.JsonGeneratorFactory;
 37  
 import java.io.InputStream;
 38  
 import java.io.OutputStream;
 39  
 import java.io.OutputStreamWriter;
 40  
 import java.io.Reader;
 41  
 import java.io.Writer;
 42  
 import java.lang.reflect.Array;
 43  
 import java.lang.reflect.InvocationTargetException;
 44  
 import java.lang.reflect.ParameterizedType;
 45  
 import java.lang.reflect.Type;
 46  
 import java.math.BigDecimal;
 47  
 import java.math.BigInteger;
 48  
 import java.util.ArrayList;
 49  
 import java.util.Collection;
 50  
 import java.util.Comparator;
 51  
 import java.util.HashMap;
 52  
 import java.util.HashSet;
 53  
 import java.util.List;
 54  
 import java.util.Map;
 55  
 import java.util.Queue;
 56  
 import java.util.Set;
 57  
 import java.util.SortedMap;
 58  
 import java.util.SortedSet;
 59  
 import java.util.TreeMap;
 60  
 import java.util.TreeSet;
 61  
 import java.util.concurrent.ArrayBlockingQueue;
 62  
 import java.util.concurrent.ConcurrentHashMap;
 63  
 import java.util.concurrent.ConcurrentMap;
 64  
 
 65  
 import static java.util.Arrays.asList;
 66  
 
 67  
 public class Mapper {
 68  1
     private static final Converter<Object> FALLBACK_CONVERTER = new FallbackConverter();
 69  1
     private static final JohnzonParameterizedType ANY_LIST = new JohnzonParameterizedType(List.class, Object.class);
 70  
 
 71  
     protected final Mappings mappings;
 72  
     protected final JsonReaderFactory readerFactory;
 73  
     protected final JsonGeneratorFactory generatorFactory;
 74  
     protected final boolean close;
 75  
     protected final ConcurrentMap<Type, Converter<?>> converters;
 76  
     protected final int version;
 77  
     private final boolean hiddenConstructorSupported;
 78  
     private final AccessMode accessMode;
 79  
     protected boolean skipNull;
 80  
     protected boolean skipEmptyArray;
 81  
 
 82  
     public Mapper(final JsonReaderFactory readerFactory, final JsonGeneratorFactory generatorFactory,
 83  
                   final boolean doClose, final Map<Class<?>, Converter<?>> converters,
 84  
                   final int version, final Comparator<String> attributeOrder, boolean skipNull, boolean skipEmptyArray,
 85  48
                   final AccessMode accessMode, final boolean hiddenConstructorSupported) {
 86  48
         this.readerFactory = readerFactory;
 87  48
         this.generatorFactory = generatorFactory;
 88  48
         this.close = doClose;
 89  48
         this.converters = new ConcurrentHashMap<Type, Converter<?>>(converters);
 90  48
         this.version = version;
 91  48
         this.mappings = new Mappings(attributeOrder, accessMode, hiddenConstructorSupported);
 92  48
         this.skipNull = skipNull;
 93  48
         this.skipEmptyArray = skipEmptyArray;
 94  48
         this.accessMode = accessMode;
 95  48
         this.hiddenConstructorSupported = hiddenConstructorSupported;
 96  48
     }
 97  
 
 98  
     private static JsonGenerator writePrimitives(final JsonGenerator generator, final Object value) {
 99  26
         if (value == null) {
 100  0
             return null; // fake a write
 101  
         }
 102  
 
 103  26
         final Class<?> type = value.getClass();
 104  26
         if (type == String.class) {
 105  6
             return generator.write(value.toString());
 106  20
         } else if (type == long.class || type == Long.class) {
 107  0
             return generator.write(Long.class.cast(value).longValue());
 108  20
         } else if (isInt(type)) {
 109  12
             return generator.write(Integer.class.cast(value).intValue());
 110  8
         } else if (isFloat(type)) {
 111  0
             return generator.write(Number.class.cast(value).doubleValue());
 112  8
         } else if (type == boolean.class || type == Boolean.class) {
 113  0
             return generator.write(Boolean.class.cast(value));
 114  8
         } else if (type == BigDecimal.class) {
 115  0
             return generator.write(BigDecimal.class.cast(value));
 116  8
         } else if (type == BigInteger.class) {
 117  0
             return generator.write(BigInteger.class.cast(value));
 118  8
         } else if (type == char.class || type == Character.class) {
 119  2
             return generator.write(Character.class.cast(value).toString());
 120  
         }
 121  6
         return null;
 122  
     }
 123  
 
 124  
     private static JsonGenerator writePrimitives(final JsonGenerator generator, final String key, final Class<?> type, final Object value) {
 125  75
         if (type == String.class) {
 126  20
             return generator.write(key, value.toString());
 127  55
         } else if (type == long.class || type == Long.class) {
 128  9
             return generator.write(key, Long.class.cast(value).longValue());
 129  46
         } else if (isInt(type)) {
 130  19
             return generator.write(key, Number.class.cast(value).intValue());
 131  27
         } else if (isFloat(type)) {
 132  6
             return generator.write(key, Number.class.cast(value).doubleValue());
 133  21
         } else if (type == boolean.class || type == Boolean.class) {
 134  12
             return generator.write(key, Boolean.class.cast(value));
 135  9
         } else if (type == BigDecimal.class) {
 136  5
             return generator.write(key, BigDecimal.class.cast(value));
 137  4
         } else if (type == BigInteger.class) {
 138  3
             return generator.write(key, BigInteger.class.cast(value));
 139  1
         } else if (type == char.class || type == Character.class) {
 140  1
             return generator.write(key, Character.class.cast(value).toString());
 141  
         }
 142  0
         return generator;
 143  
     }
 144  
 
 145  
     private static boolean isInt(final Class<?> type) {
 146  66
         return type == int.class || type == Integer.class
 147  
                 || type == byte.class || type == Byte.class
 148  
                 || type == short.class || type == Short.class;
 149  
     }
 150  
 
 151  
     private static boolean isFloat(final Class<?> type) {
 152  35
         return type == double.class || type == Double.class
 153  
                 || type == float.class || type == Float.class;
 154  
     }
 155  
 
 156  
     /*private <T> String convertFrom(final Class<T> aClass, final T value) {
 157  
         final Converter<T> converter = (Converter<T>) findConverter(aClass);
 158  
         return doConverFrom(value, converter);
 159  
     }*/
 160  
 
 161  
     private static <T> String doConverFrom(final T value, final Converter<T> converter) {
 162  0
         if (converter == null) {
 163  0
             throw new MapperException("can't convert " + value + " to String");
 164  
         }
 165  0
         return converter.toString(value);
 166  
     }
 167  
 
 168  
     private <T> Converter<T> findConverter(final Type aClass) {
 169  51
         final Converter<T> converter = (Converter<T>) converters.get(aClass);
 170  51
         if (converter != null) {
 171  48
             return converter;
 172  
         }
 173  3
         if (Class.class.isInstance(aClass)) {
 174  2
             final Class<?> clazz = Class.class.cast(aClass);
 175  2
             if (clazz.isEnum()) {
 176  0
                 final Converter<T> enumConverter = new EnumConverter(clazz);
 177  0
                 converters.putIfAbsent(clazz, enumConverter);
 178  0
                 return enumConverter;
 179  
             }
 180  
         }
 181  3
         return null;
 182  
     }
 183  
 
 184  
     private Object convertTo(final Type aClass, final String text) {
 185  51
         if (Object.class == aClass) {
 186  2
             return text;
 187  
         }
 188  49
         final Converter<?> converter = findConverter(aClass);
 189  49
         if (converter == null) {
 190  1
             converters.putIfAbsent(aClass, FALLBACK_CONVERTER);
 191  1
             return FALLBACK_CONVERTER;
 192  
         }
 193  48
         return converter.fromString(text);
 194  
     }
 195  
 
 196  
     public <T> void writeArray(final Object object, final OutputStream stream) {
 197  0
         writeArray(asList((T[]) object), stream);
 198  0
     }
 199  
 
 200  
     public <T> void writeArray(final T[] object, final OutputStream stream) {
 201  2
         writeArray(asList(object), stream);
 202  2
     }
 203  
 
 204  
     public <T> void writeArray(final T[] object, final Writer stream) {
 205  0
         writeArray(asList(object), stream);
 206  0
     }
 207  
 
 208  
     public <T> void writeArray(final Collection<T> object, final OutputStream stream) {
 209  2
         writeArray(object, new OutputStreamWriter(stream));
 210  2
     }
 211  
 
 212  
     public <T> void writeArray(final Collection<T> object, final Writer stream) {
 213  2
         JsonGenerator generator = generatorFactory.createGenerator(stream);
 214  
         try {
 215  2
             if (object == null) {
 216  0
                 generator = generator.writeStartArray().writeEnd();
 217  
             } else {
 218  2
                 generator = generator.writeStartArray();
 219  2
                 for (final T t : object) {
 220  4
                     generator = writeItem(generator, t);
 221  4
                 }
 222  2
                 generator = generator.writeEnd();
 223  
             }
 224  
         } finally {
 225  2
             doCloseOrFlush(generator);
 226  2
         }
 227  2
     }
 228  
 
 229  
     private void doCloseOrFlush(JsonGenerator generator) {
 230  25
         if (close) {
 231  0
             generator.close();
 232  
         } else {
 233  25
             generator.flush();
 234  
         }
 235  25
     }
 236  
 
 237  
     public <T> void writeIterable(final Iterable<T> object, final OutputStream stream) {
 238  0
         writeIterable(object, new OutputStreamWriter(stream));
 239  0
     }
 240  
 
 241  
     public <T> void writeIterable(final Iterable<T> object, final Writer stream) {
 242  0
         JsonGenerator generator = generatorFactory.createGenerator(stream);
 243  
         try {
 244  0
             if (object == null) {
 245  0
                 generator = generator.writeStartArray().writeEnd();
 246  
             } else {
 247  0
                 generator.writeStartArray();
 248  0
                 for (final T t : object) {
 249  0
                     generator = writeItem(generator, t);
 250  0
                 }
 251  0
                 generator.writeEnd();
 252  
             }
 253  
         } finally {
 254  0
             doCloseOrFlush(generator);
 255  0
         }
 256  0
     }
 257  
 
 258  
     public void writeObject(final Object object, final Writer stream) {
 259  24
         final JsonGenerator generator = generatorFactory.createGenerator(stream);
 260  24
         doWriteHandlingNullObject(object, generator);
 261  22
     }
 262  
 
 263  
     public void writeObject(final Object object, final OutputStream stream) {
 264  1
         final JsonGenerator generator = generatorFactory.createGenerator(stream);
 265  1
         doWriteHandlingNullObject(object, generator);
 266  1
     }
 267  
 
 268  
     private void doWriteHandlingNullObject(final Object object, final JsonGenerator generator) {
 269  25
         if (object == null) {
 270  2
             generator.writeStartObject().writeEnd().close();
 271  2
             return;
 272  
         }
 273  
 
 274  
         //JsonGenerator gen = null;
 275  
         try {
 276  
             /*gen = */
 277  23
             doWriteObject(generator, object);
 278  
         } finally {
 279  23
             doCloseOrFlush(generator);
 280  21
         }
 281  21
     }
 282  
 
 283  
     private JsonGenerator doWriteObject(final JsonGenerator generator, final Object object) {
 284  
         try {
 285  29
             JsonGenerator gen = generator;
 286  29
             if (object == null) {
 287  0
                 return generator;
 288  
             }
 289  
 
 290  29
             if (Map.class.isInstance(object)) {
 291  1
                 gen = gen.writeStartObject();
 292  1
                 gen = writeMapBody((Map<?, ?>) object, gen);
 293  1
                 gen = gen.writeEnd();
 294  1
                 return gen;
 295  
             }
 296  
 
 297  28
             gen = gen.writeStartObject();
 298  28
             gen = doWriteObjectBody(gen, object);
 299  26
             return gen.writeEnd();
 300  0
         } catch (final InvocationTargetException e) {
 301  0
             throw new MapperException(e);
 302  0
         } catch (final IllegalAccessException e) {
 303  0
             throw new MapperException(e);
 304  
         }
 305  
     }
 306  
 
 307  
     private JsonGenerator doWriteObjectBody(final JsonGenerator gen, final Object object) throws IllegalAccessException, InvocationTargetException {
 308  30
         final Class<?> objectClass = object.getClass();
 309  30
         final Mappings.ClassMapping classMapping = mappings.findOrCreateClassMapping(objectClass);
 310  30
         if (classMapping == null) {
 311  0
             throw new MapperException("No mapping for " + objectClass.getName());
 312  
         }
 313  
 
 314  30
         JsonGenerator generator = gen;
 315  30
         for (final Map.Entry<String, Mappings.Getter> getterEntry : classMapping.getters.entrySet()) {
 316  131
             final Mappings.Getter getter = getterEntry.getValue();
 317  131
             final Object value = getter.reader.read(object);
 318  131
             if (getter.version >= 0 && version >= getter.version) {
 319  2
                 continue;
 320  
             }
 321  
 
 322  129
             if (value == null) {
 323  43
                 if (skipNull) {
 324  37
                     continue;
 325  
                 } else {
 326  6
                     gen.writeNull(getterEntry.getKey());
 327  6
                     continue;
 328  
                 }
 329  
             }
 330  
 
 331  86
             generator = writeValue(generator, value.getClass(),
 332  
                     getter.primitive, getter.array,
 333  
                     getter.collection, getter.map,
 334  
                     getterEntry.getKey(),
 335  
                     getter.converter == null ? value : getter.converter.toString(value));
 336  84
         }
 337  28
         return generator;
 338  
     }
 339  
 
 340  
     private JsonGenerator writeMapBody(final Map<?, ?> object, final JsonGenerator gen) throws InvocationTargetException, IllegalAccessException {
 341  7
         JsonGenerator generator = gen;
 342  7
         for (final Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
 343  14
             final Object value = entry.getValue();
 344  14
             final Object key = entry.getKey();
 345  
 
 346  14
             if (value == null) {
 347  2
                 if (skipNull) {
 348  1
                     continue;
 349  
                 } else {
 350  1
                     gen.writeNull(key == null ? "null" : key.toString());
 351  1
                     continue;
 352  
                 }
 353  
             }
 354  
 
 355  12
             final Class<?> valueClass = value.getClass();
 356  12
             final boolean primitive = Mappings.isPrimitive(valueClass);
 357  12
             final boolean clazz = mappings.getClassMapping(valueClass) != null;
 358  12
             final boolean array = clazz || primitive ? false : valueClass.isArray();
 359  12
             final boolean collection = clazz || primitive || array ? false : Collection.class.isAssignableFrom(valueClass);
 360  12
             final boolean map = clazz || primitive || array || collection ? false : Map.class.isAssignableFrom(valueClass);
 361  12
             generator = writeValue(generator, valueClass,
 362  
                     primitive, array, collection, map,
 363  
                     key == null ? "null" : key.toString(), value);
 364  12
         }
 365  7
         return generator;
 366  
     }
 367  
 
 368  
     private JsonGenerator writeValue(final JsonGenerator generator, final Class<?> type,
 369  
                                      final boolean primitive, final boolean array,
 370  
                                      final boolean collection, final boolean map,
 371  
                                      final String key, final Object value) throws InvocationTargetException, IllegalAccessException {
 372  98
         if (array) {
 373  7
             final int length = Array.getLength(value);
 374  7
             if (length == 0 && skipEmptyArray) {
 375  2
                 return generator;
 376  
             }
 377  
 
 378  5
             JsonGenerator gen = generator.writeStartArray(key);
 379  14
             for (int i = 0; i < length; i++) {
 380  9
                 gen = writeItem(gen, Array.get(value, i));
 381  
             }
 382  5
             return gen.writeEnd();
 383  91
         } else if (collection) {
 384  8
             JsonGenerator gen = generator.writeStartArray(key);
 385  8
             for (final Object o : Collection.class.cast(value)) {
 386  13
                 gen = writeItem(gen, o);
 387  13
             }
 388  8
             return gen.writeEnd();
 389  83
         } else if (map) {
 390  6
             JsonGenerator gen = generator.writeStartObject(key);
 391  6
             gen = writeMapBody((Map<?, ?>) value, gen);
 392  6
             return gen.writeEnd();
 393  77
         } else if (primitive) {
 394  75
             return writePrimitives(generator, key, type, value);
 395  
         } else {
 396  2
             final Converter<?> converter = findConverter(type);
 397  2
             if (converter != null) {
 398  0
                 return writeValue(generator, String.class, true, false, false, false, key,
 399  
                         doConverFrom(value, (Converter<Object>) converter));
 400  
             }
 401  2
             return doWriteObjectBody(generator.writeStartObject(key), value).writeEnd();
 402  
         }
 403  
     }
 404  
 
 405  
     private JsonGenerator writeItem(final JsonGenerator generator, final Object o) {
 406  26
         final JsonGenerator newGen = writePrimitives(generator, o);
 407  26
         if (newGen == null) {
 408  6
             return doWriteObject(generator, o);
 409  
         }
 410  20
         return newGen;
 411  
     }
 412  
 
 413  
     public <T> T readObject(final Reader stream, final Type clazz) {
 414  6
         final JsonReader reader = readerFactory.createReader(stream);
 415  6
         return mapObject(clazz, reader);
 416  
     }
 417  
 
 418  
     public <T> T readObject(final InputStream stream, final Type clazz) {
 419  11
         final JsonReader reader = readerFactory.createReader(stream);
 420  11
         return mapObject(clazz, reader);
 421  
     }
 422  
 
 423  
     private <T> T mapObject(final Type clazz, final JsonReader reader) {
 424  
         try {
 425  17
             return (T) buildObject(clazz, reader.readObject());
 426  3
         } catch (final Exception e) {
 427  3
             throw new MapperException(e);
 428  
         } finally {
 429  17
             if (close) {
 430  0
                 reader.close();
 431  
             }
 432  
         }
 433  
     }
 434  
 
 435  
     public <T> Collection<T> readCollection(final InputStream stream, final ParameterizedType genericType) {
 436  2
         final JsonReader reader = readerFactory.createReader(stream);
 437  2
         final Mappings.CollectionMapping mapping = mappings.findCollectionMapping(genericType);
 438  2
         if (mapping == null) {
 439  0
             throw new UnsupportedOperationException("type " + genericType + " not supported");
 440  
         }
 441  
         try {
 442  2
             return mapCollection(mapping, reader.readArray());
 443  0
         } catch (final Exception e) {
 444  0
             throw new MapperException(e);
 445  
         } finally {
 446  2
             if (close) {
 447  0
                 reader.close();
 448  
             }
 449  
         }
 450  
     }
 451  
 
 452  
     public <T> T readJohnzonCollection(final InputStream stream, final JohnzonCollectionType<T> genericType) {
 453  1
         return (T) readCollection(stream, genericType);
 454  
     }
 455  
 
 456  
     public <T> T readJohnzonCollection(final Reader stream, final JohnzonCollectionType<T> genericType) {
 457  0
         return (T) readCollection(stream, genericType);
 458  
     }
 459  
 
 460  
     public <T> Collection<T> readCollection(final Reader stream, final ParameterizedType genericType) {
 461  0
         final JsonReader reader = readerFactory.createReader(stream);
 462  0
         final Mappings.CollectionMapping mapping = mappings.findCollectionMapping(genericType);
 463  0
         if (mapping == null) {
 464  0
             throw new UnsupportedOperationException("type " + genericType + " not supported");
 465  
         }
 466  
         try {
 467  0
             return mapCollection(mapping, reader.readArray());
 468  0
         } catch (final Exception e) {
 469  0
             throw new MapperException(e);
 470  
         } finally {
 471  0
             if (close) {
 472  0
                 reader.close();
 473  
             }
 474  
         }
 475  
     }
 476  
 
 477  
     public <T> T[] readArray(final Reader stream, final Class<T> clazz) {
 478  0
         final JsonReader reader = readerFactory.createReader(stream);
 479  0
         return mapArray(clazz, reader);
 480  
     }
 481  
 
 482  
     public <T> T[] readArray(final InputStream stream, final Class<T> clazz) {
 483  2
         final JsonReader reader = readerFactory.createReader(stream);
 484  2
         return mapArray(clazz, reader);
 485  
     }
 486  
 
 487  
     private <T> T[] mapArray(final Class<T> clazz, final JsonReader reader) {
 488  
         try {
 489  2
             return (T[]) buildArrayWithComponentType(reader.readArray(), clazz);
 490  0
         } catch (final Exception e) {
 491  0
             throw new MapperException(e);
 492  
         } finally {
 493  2
             if (close) {
 494  0
                 reader.close();
 495  
             }
 496  
         }
 497  
     }
 498  
 
 499  
     private Object buildObject(final Type type, final JsonObject object) throws Exception {
 500  44
         final Mappings.ClassMapping classMapping = mappings.findOrCreateClassMapping(type);
 501  
 
 502  44
         if (classMapping == null) {
 503  8
             if (ParameterizedType.class.isInstance(type)) {
 504  8
                 final ParameterizedType aType = ParameterizedType.class.cast(type);
 505  8
                 final Type[] fieldArgTypes = aType.getActualTypeArguments();
 506  8
                 if (fieldArgTypes.length >= 2) {
 507  8
                     final Class<?> raw = Class.class.cast(aType.getRawType());
 508  
 
 509  
                     final Map map;
 510  8
                     if (SortedMap.class.isAssignableFrom(raw)) {
 511  1
                         map = new TreeMap();
 512  7
                     } else if (ConcurrentMap.class.isAssignableFrom(raw)) {
 513  0
                         map = new ConcurrentHashMap(object.size());
 514  7
                     } else if (Map.class.isAssignableFrom(raw)) {
 515  7
                         map = new HashMap(object.size());
 516  
                     } else {
 517  0
                         map = null;
 518  
                     }
 519  
 
 520  8
                     if (map != null) {
 521  
 
 522  
                         Type keyType;
 523  8
                         if (ParameterizedType.class.isInstance(fieldArgTypes[0])) {
 524  2
                             keyType = fieldArgTypes[0];
 525  
                         } else {
 526  6
                             keyType = fieldArgTypes[0];
 527  
                         }
 528  
 
 529  8
                         for (final Map.Entry<String, JsonValue> value : object.entrySet()) {
 530  16
                             map.put(convertTo(keyType, value.getKey()), toObject(value.getValue(), fieldArgTypes[1]));
 531  14
                         }
 532  6
                         return map;
 533  
                     }
 534  
                 }
 535  
             }
 536  
         }
 537  36
         if (classMapping == null) {
 538  0
             throw new MapperException("Can't map " + type);
 539  
         }
 540  
 
 541  36
         if (classMapping.constructor == null) {
 542  0
             throw new IllegalArgumentException(classMapping.clazz.getName() + " can't be instantiated by Johnzon, this is a write only class");
 543  
         }
 544  
 
 545  36
         final Object t = classMapping.constructor.newInstance();
 546  36
         for (final Map.Entry<String, Mappings.Setter> setter : classMapping.setters.entrySet()) {
 547  261
             final JsonValue jsonValue = object.get(setter.getKey());
 548  261
             final Mappings.Setter value = setter.getValue();
 549  261
             final AccessMode.Writer setterMethod = value.writer;
 550  261
             final Object convertedValue = value.converter == null ?
 551  
                     toObject(jsonValue, value.paramType) : jsonValue.getValueType() == ValueType.STRING ?
 552  
                     value.converter.fromString(JsonString.class.cast(jsonValue).getString()) :
 553  
                     value.converter.fromString(jsonValue.toString());
 554  
 
 555  258
             if (convertedValue != null) {
 556  113
                 setterMethod.write(t, convertedValue);
 557  
             }
 558  258
         }
 559  
 
 560  33
         return t;
 561  
     }
 562  
 
 563  
     private Object toObject(final JsonValue jsonValue, final Type type) throws Exception {
 564  333
         if (jsonValue == null || jsonValue == JsonValue.NULL) {
 565  146
             return null;
 566  
         }
 567  
 
 568  187
         if (type == Boolean.class || type == boolean.class) {
 569  18
             if (jsonValue == JsonValue.TRUE) {
 570  8
                 return true;
 571  
             }
 572  10
             if (jsonValue == JsonValue.FALSE) {
 573  8
                 return false;
 574  
             }
 575  2
             throw new MapperException("Unable to parse " + jsonValue + " to boolean");
 576  
         }
 577  
 
 578  169
         if (Object.class == type) { // handling specific types here to keep exception in standard handling
 579  8
             if (jsonValue == JsonValue.TRUE) {
 580  1
                 return true;
 581  
             }
 582  7
             if (jsonValue == JsonValue.FALSE) {
 583  0
                 return false;
 584  
             }
 585  7
             if (JsonNumber.class.isInstance(jsonValue)) {
 586  3
                 return JsonNumber.class.cast(jsonValue).intValue();
 587  
             }
 588  
         }
 589  
 
 590  165
         if (type == Character.class || type == char.class) {
 591  3
             return convertTo(Class.class.cast(type), (JsonString.class.cast(jsonValue).getString()));
 592  
         }
 593  
 
 594  162
         if (JsonObject.class.isInstance(jsonValue)) {
 595  27
             return buildObject(type, JsonObject.class.cast(jsonValue));
 596  135
         } else if (JsonArray.class.isInstance(jsonValue)) {
 597  21
             return buildArray(type, JsonArray.class.cast(jsonValue));
 598  114
         } else if (JsonNumber.class.isInstance(jsonValue)) {
 599  
 
 600  82
             final JsonNumber number = JsonNumber.class.cast(jsonValue);
 601  
 
 602  82
             if (type == Integer.class || type == int.class) {
 603  53
                 return number.intValue();
 604  
             }
 605  
 
 606  29
             if (type == Long.class || type == long.class) {
 607  22
                 return number.longValue();
 608  
             }
 609  
 
 610  7
             if (type == Short.class || type == short.class) {
 611  1
                 return (short) number.intValue();
 612  
             }
 613  
 
 614  6
             if (type == Byte.class || type == byte.class) {
 615  1
                 return (byte) number.intValue();
 616  
             }
 617  
 
 618  5
             if (type == Float.class || type == float.class) {
 619  1
                 return (float) number.doubleValue();
 620  
             }
 621  
 
 622  4
             if (type == Double.class || type == double.class) {
 623  1
                 return number.doubleValue();
 624  
             }
 625  
 
 626  3
             if (type == BigInteger.class) {
 627  1
                 return number.bigIntegerValue();
 628  
             }
 629  
 
 630  2
             if (type == BigDecimal.class) {
 631  2
                 return number.bigDecimalValue();
 632  
             }
 633  0
         } else if (JsonString.class.isInstance(jsonValue) || Object.class == type) {
 634  32
             return convertTo(Class.class.cast(type), JsonString.class.cast(jsonValue).getString());
 635  
         }
 636  
 
 637  0
         throw new MapperException("Unable to parse " + jsonValue + " to " + type);
 638  
     }
 639  
 
 640  
     private Object buildArray(final Type type, final JsonArray jsonArray) throws Exception {
 641  23
         if (Class.class.isInstance(type)) {
 642  9
             final Class clazz = Class.class.cast(type);
 643  9
             if (clazz.isArray()) {
 644  7
                 final Class<?> componentType = clazz.getComponentType();
 645  7
                 return buildArrayWithComponentType(jsonArray, componentType);
 646  
             }
 647  
         }
 648  
 
 649  16
         if (ParameterizedType.class.isInstance(type)) {
 650  14
             final Mappings.CollectionMapping mapping = mappings.findCollectionMapping(ParameterizedType.class.cast(type));
 651  14
             if (mapping != null) {
 652  14
                 return mapCollection(mapping, jsonArray);
 653  
             }
 654  
         }
 655  
 
 656  2
         if (Object.class == type) {
 657  2
             return buildArray(ANY_LIST, jsonArray);
 658  
         }
 659  
 
 660  0
         throw new UnsupportedOperationException("type " + type + " not supported");
 661  
     }
 662  
 
 663  
     private <T> Collection<T> mapCollection(final Mappings.CollectionMapping mapping, final JsonArray jsonArray) throws Exception {
 664  
         final Collection collection;
 665  
 
 666  16
         if (SortedSet.class == mapping.raw) {
 667  3
             collection = new TreeSet<T>();
 668  13
         } else if (Set.class == mapping.raw) {
 669  0
             collection = new HashSet<T>(jsonArray.size());
 670  13
         } else if (Queue.class == mapping.raw) {
 671  1
             collection = new ArrayBlockingQueue<T>(jsonArray.size());
 672  12
         } else if (List.class == mapping.raw || Collection.class == mapping.raw) {
 673  12
             collection = new ArrayList<T>(jsonArray.size());
 674  
         } else {
 675  0
             throw new IllegalStateException("not supported collection type: " + mapping.raw.getName());
 676  
         }
 677  
 
 678  16
         for (final JsonValue value : jsonArray) {
 679  33
             final Object element = toObject(value, mapping.arg);
 680  33
             collection.add(element);
 681  33
         }
 682  16
         return collection;
 683  
     }
 684  
 
 685  
     private Object buildArrayWithComponentType(final JsonArray jsonArray, final Class<?> componentType) throws Exception {
 686  9
         final Object array = Array.newInstance(componentType, jsonArray.size());
 687  9
         int i = 0;
 688  9
         for (final JsonValue value : jsonArray) {
 689  25
             Array.set(array, i++, toObject(value, componentType));
 690  25
         }
 691  9
         return array;
 692  
     }
 693  
 
 694  2
     private static class FallbackConverter implements Converter<Object> {
 695  
         @Override
 696  
         public String toString(final Object instance) {
 697  0
             return instance.toString();
 698  
         }
 699  
 
 700  
         @Override
 701  
         public Object fromString(final String text) {
 702  1
             throw new UnsupportedOperationException("Using fallback converter, " +
 703  
                     "this only works in write mode but not in read. Please register a custom converter to do so.");
 704  
         }
 705  
     }
 706  
 }