All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.mmm.util.json.base.JsonUtilImpl Maven / Gradle / Ivy

The newest version!
/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0
 * http://www.apache.org/licenses/LICENSE-2.0 */
package net.sf.mmm.util.json.base;

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.inject.Inject;
import javax.json.stream.JsonGenerator;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;

import net.sf.mmm.util.collection.api.CollectionFactoryManager;
import net.sf.mmm.util.collection.impl.CollectionFactoryManagerImpl;
import net.sf.mmm.util.component.base.AbstractComponent;
import net.sf.mmm.util.json.api.JsonSupport;
import net.sf.mmm.util.json.api.JsonUtil;
import net.sf.mmm.util.reflect.api.GenericType;
import net.sf.mmm.util.reflect.base.EnumHelper;

/**
 * The implementation of {@link JsonUtil}.
 *
 * @see #getInstance()
 *
 * @author hohwille
 * @since 7.4.0
 */
public class JsonUtilImpl extends AbstractComponent implements JsonUtil {

  private static JsonUtil instance;

  private CollectionFactoryManager collectionFactoryManager;

  /**
   * The constructor.
   */
  public JsonUtilImpl() {

    super();
  }

  /**
   * @param collectionFactoryManager is the {@link CollectionFactoryManager} to {@link Inject}.
   */
  @Inject
  public void setCollectionReflectionUtil(CollectionFactoryManager collectionFactoryManager) {

    this.collectionFactoryManager = collectionFactoryManager;
  }

  @Override
  protected void doInitialize() {

    super.doInitialize();
    if (this.collectionFactoryManager == null) {
      this.collectionFactoryManager = CollectionFactoryManagerImpl.getInstance();
    }
  }

  @Override
  protected void doInitialized() {

    super.doInitialized();
    if (instance == null) {
      instance = this;
    }
  }

  /**
   * This method gets the singleton instance of this {@link JsonUtilImpl}. 
* ATTENTION:
* Please prefer dependency-injection instead of using this method. * * @return the singleton instance. */ public static JsonUtil getInstance() { if (instance == null) { synchronized (JsonUtilImpl.class) { if (instance == null) { JsonUtilImpl impl = new JsonUtilImpl(); impl.initialize(); } } } return instance; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public T read(JsonParser json, GenericType type, Event e) { if (e == Event.VALUE_NULL) { return null; } Class valueClass = type.getAssignmentClass(); Object result; if ((valueClass == String.class) || (valueClass == CharSequence.class)) { expectEvent(e, Event.VALUE_STRING); result = json.getString(); } else if (Number.class.isAssignableFrom(valueClass)) { expectEvent(e, Event.VALUE_NUMBER); result = readNumber(json, (Class) valueClass); } else if ((valueClass == Boolean.class) || (valueClass == boolean.class)) { result = Boolean.valueOf(readBoolean(e)); } else if (valueClass.isEnum()) { expectEvent(e, Event.VALUE_STRING); result = readEnum(json, (Class) valueClass); } else if (Collection.class.isAssignableFrom(valueClass)) { expectEvent(e, Event.START_ARRAY); result = readCollection(json, (GenericType>) type); } else if (valueClass.isArray()) { expectEvent(e, Event.START_ARRAY); GenericType componentType = type.getComponentType(); List list = new ArrayList<>(); readCollection(json, (Collection) list, componentType); result = Array.newInstance(componentType.getRetrievalClass(), list.size()); result = list.toArray((Object[]) result); } else if (Map.class.isAssignableFrom(valueClass)) { expectEvent(e, Event.START_OBJECT); result = readMap(json, (GenericType) type); } else { throw new IllegalArgumentException(type.toString()); } return (T) result; } @Override public > E readEnum(JsonParser json, Class enumType) { String value = json.getString(); return convertEnum(value, enumType); } /** * @param the generic type of the {@link Enum} to parse. * @param value the value to convert to the {@link Enum}. * @param enumType the {@link Class} reflecting the {@link Enum} to parse. * @return the parsed {@link Enum} constant. * @throws IllegalStateException if no such {@link Enum} constant exists. */ protected > E convertEnum(String value, Class enumType) { return EnumHelper.fromString(value, enumType); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public > C readCollection(JsonParser json, GenericType type) { C collection = this.collectionFactoryManager.create(type.getAssignmentClass()); readCollection(json, (Collection) collection, type.getComponentType()); return collection; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public void readCollection(JsonParser json, Collection collection, GenericType type) { Collection c = collection; Event e = json.next(); while (e != Event.END_ARRAY) { Object item = read(json, type, e); c.add(item); e = json.next(); } } @Override @SuppressWarnings({ "rawtypes", "unchecked" }) public > M readMap(JsonParser json, GenericType type) { M map = this.collectionFactoryManager.createMap(type.getAssignmentClass()); readMap(json, map, (GenericType) type.getKeyType(), (GenericType) type.getComponentType()); return map; } @Override public void readMap(JsonParser json, Map map, GenericType keyType, GenericType valueType) { Event e = json.next(); while (e != Event.END_OBJECT) { expectEvent(e, Event.KEY_NAME); String keyString = json.getString(); K key = convert(keyString, keyType); V value = read(json, valueType); map.put(key, value); e = json.next(); } } /** * @param the generic type of the value to parse. * @param value the value as {@link String}. * @param type the {@link GenericType} of the value to parse. * @return the given {@code value} parsed as the expected {@link GenericType}. */ @SuppressWarnings({ "rawtypes", "unchecked" }) protected V convert(String value, GenericType type) { Object result; Class valueClass = type.getAssignmentClass(); if ((type == null) || (valueClass == String.class) || (valueClass == CharSequence.class)) { result = value; } else if (Number.class.isAssignableFrom(valueClass)) { result = convertNumber(value, (Class) valueClass); } else if (valueClass.isEnum()) { result = convertEnum(value, (Class) valueClass); } else if ((valueClass == boolean.class) || (valueClass == Boolean.class)) { result = Boolean.valueOf(value); } else { throw new IllegalArgumentException(type.toString()); } return (V) result; } @SuppressWarnings("rawtypes") @Override public void write(JsonGenerator json, String property, Object value) { if (value == null) { writeNull(json, property); } else if (value instanceof JsonSupport) { if (property != null) { json.writeStartObject(property); } ((JsonSupport) value).toJson(json); if (property != null) { json.writeEnd(); } } else if (value instanceof Number) { write(json, property, (Number) value); } else if (value instanceof Boolean) { boolean booleanValue = ((Boolean) value).booleanValue(); write(json, property, booleanValue); } else if (value.getClass().isArray()) { int length = Array.getLength(value); if (property == null) { json.writeStartArray(); } else { json.writeStartArray(property); } for (int i = 0; i < length; i++) { write(json, null, Array.get(value, i)); } json.writeEnd(); } else if (value instanceof Iterable) { write(json, property, (Iterable) value); } else if (value instanceof Map) { write(json, property, (Map) value); } else { String string = value.toString(); write(json, property, string); } } @Override public void write(JsonGenerator json, String property, String value) { if (value == null) { writeNull(json, property); return; } if (property == null) { json.write(value); } else { json.write(property, value); } } @Override public void write(JsonGenerator json, String property, boolean value) { if (property == null) { json.write(value); } else { json.write(property, value); } } @Override public void write(JsonGenerator json, String property, Number value) { if (value instanceof Long) { write(json, property, value.longValue()); } else if ((value instanceof Integer) || (value instanceof Short) || (value instanceof Byte)) { write(json, property, value.intValue()); } else if (value instanceof BigDecimal) { write(json, property, value); } else if (value instanceof BigInteger) { write(json, property, value); } else { if (value == null) { writeNull(json, property); return; } write(json, property, value.doubleValue()); } } @Override public void write(JsonGenerator json, String property, long value) { if (property == null) { json.write(value); } else { json.write(property, value); } } @Override public void write(JsonGenerator json, String property, double value) { if (property == null) { json.write(value); } else { json.write(property, value); } } @Override public void write(JsonGenerator json, String property, BigDecimal value) { if (value == null) { writeNull(json, property); return; } if (property == null) { json.write(value); } else { json.write(property, value); } } @Override public void write(JsonGenerator json, String property, BigInteger value) { if (value == null) { writeNull(json, property); return; } if (property == null) { json.write(value); } else { json.write(property, value); } } @Override public void write(JsonGenerator json, String property, int value) { if (property == null) { json.write(value); } else { json.write(property, value); } } @Override public void writeNull(JsonGenerator json, String property) { if (property == null) { json.writeNull(); } } @Override public void write(JsonGenerator json, String property, Iterable value) { if (value == null) { writeNull(json, property); return; } if (property == null) { json.writeStartArray(); } else { json.writeStartArray(property); } for (Object item : value) { write(json, null, item); } json.writeEnd(); } @Override public void write(JsonGenerator json, String property, Map value) { if (value == null) { writeNull(json, property); return; } if (property == null) { json.writeStartObject(); } else { json.writeStartObject(property); } for (Entry entry : value.entrySet()) { Object key = entry.getKey(); String keyString = "null"; if (key != null) { keyString = key.toString(); } write(json, keyString, entry.getValue()); } json.writeEnd(); } @Override public void write(JsonGenerator json, String property, Object[] value) { if (value == null) { writeNull(json, property); return; } if (property == null) { json.writeStartArray(); } else { json.writeStartArray(property); } for (Object item : value) { write(json, null, item); } json.writeEnd(); } @Override public void expectEvent(JsonParser json, Event event) { Event e = json.next(); expectEvent(e, event); } @Override public void expectEvent(Event actual, Event expected) { if (actual != expected) { throw new IllegalStateException("Expecting event '" + expected + "' but found '" + actual + "'."); } } @Override public T read(JsonParser json, GenericType type) { return read(json, type, json.next()); } @Override public boolean readBoolean(Event e) { if (e == Event.VALUE_TRUE) { return true; } else if (e == Event.VALUE_FALSE) { return false; } throw new IllegalStateException("Expecting boolean value but found: " + e); } @Override public N readNumber(JsonParser json, Class type) { String value = json.getString(); return convertNumber(value, type); } /** * @param the generic type of the {@link Number} to parse. * @param value the numeric value as {@link String}. * @param type the {@link Class} reflecting the type of {@link Number} to parse. * @return the parsed value. */ @SuppressWarnings("unchecked") protected N convertNumber(String value, Class type) { Number result; if ((type == Long.class) || (type == long.class)) { result = Long.valueOf(value); } else if ((type == Integer.class) || (type == int.class)) { result = Integer.valueOf(value); } else if ((type == Double.class) || (type == double.class)) { result = Double.valueOf(value); } else if ((type == Float.class) || (type == float.class)) { result = Float.valueOf(value); } else if ((type == Short.class) || (type == short.class)) { result = Short.valueOf(value); } else if ((type == Byte.class) || (type == byte.class)) { result = Byte.valueOf(value); } else if (type == BigInteger.class) { result = new BigInteger(value); } else if (type == BigDecimal.class) { result = new BigDecimal(value); } else { throw new IllegalArgumentException(type.getName()); } return (N) result; } @Override public void skipValue(JsonParser json) { skipValue(json, json.next()); } @Override public void skipValue(JsonParser json, Event e) { Event event; switch (e) { case VALUE_FALSE: case VALUE_NULL: case VALUE_NUMBER: case VALUE_STRING: case VALUE_TRUE: break; case START_ARRAY: event = json.next(); while (event != Event.END_ARRAY) { skipValue(json, event); } break; case START_OBJECT: event = json.next(); while (event != Event.END_OBJECT) { expectEvent(event, Event.KEY_NAME); skipValue(json); } break; default : throw new IllegalStateException("Unhandled event: " + e); } } }