/**
This file is part of Waarp Project.
Copyright 2009, Frederic Bregier, and individual contributors by the @author
tags. See the COPYRIGHT.txt in the distribution for a full listing of
individual contributors.
All Waarp Project is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Waarp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Waarp . If not, see <http://www.gnu.org/licenses/>.
*/
package org.waarp.common.json;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.format.DataFormatDetector;
import com.fasterxml.jackson.core.format.DataFormatMatcher;
import com.fasterxml.jackson.core.format.MatchStrength;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
/**
* JSON handler using adaptative format (Smile or Json - in that order -)
*
* @author "Frederic Bregier"
*
*/
public class AdaptativeJsonHandler {
public static enum JsonCodec {
SMILE(new SmileFactory()), JSON(new JsonFactory());
public final JsonFactory factory;
public final ObjectMapper mapper;
private JsonCodec(JsonFactory factory) {
this.factory = factory;
this.mapper = new ObjectMapper(factory);
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
}
private static List<JsonFactory> getFactories() {
List<JsonFactory> factories = new ArrayList<JsonFactory>();
JsonCodec[] codecs = JsonCodec.values();
for (JsonCodec jsonCodec : codecs) {
factories.add(jsonCodec.factory);
}
return factories;
}
private static HashMap<String, JsonCodec> getHashMap() {
HashMap<String, JsonCodec> hashmap = new HashMap<String, JsonCodec>();
JsonCodec[] codecs = JsonCodec.values();
for (JsonCodec jsonCodec : codecs) {
hashmap.put(jsonCodec.factory.getFormatName(), jsonCodec);
}
return hashmap;
}
}
/**
* Data Format Detector
*/
private static final DataFormatDetector detector = new DataFormatDetector(JsonCodec.getFactories())
.withMinimalMatch(MatchStrength.WEAK_MATCH)
.withOptimalMatch(MatchStrength.SOLID_MATCH);
/**
* HashMap getting Codec from Factory name
*/
private static final HashMap<String, JsonCodec> factoryForName = JsonCodec.getHashMap();
ObjectMapper mapper;
private JsonCodec codec;
public AdaptativeJsonHandler(JsonCodec codec) {
this.codec = codec;
mapper = codec.mapper;
}
public AdaptativeJsonHandler(byte[] source) throws IOException {
DataFormatMatcher match = detector.findFormat(source);
if (match == null) {
this.codec = JsonCodec.JSON;
mapper = JsonCodec.JSON.mapper; // default
} else {
JsonCodec codec = factoryForName.get(match.getMatchedFormatName());
if (codec != null) {
this.codec = codec;
mapper = codec.mapper;
} else {
this.codec = JsonCodec.JSON;
mapper = JsonCodec.JSON.mapper; // default
}
}
}
public AdaptativeJsonHandler(InputStream source) throws IOException {
DataFormatMatcher match = detector.findFormat(source);
if (match == null) {
this.codec = JsonCodec.JSON;
mapper = JsonCodec.JSON.mapper; // default
} else {
JsonCodec codec = factoryForName.get(match.getMatchedFormatName());
if (codec != null) {
this.codec = codec;
mapper = codec.mapper;
} else {
this.codec = JsonCodec.JSON;
mapper = JsonCodec.JSON.mapper; // default
}
}
}
/**
* Change the JsonCodec: warning, change should be done before any usage to preserve consistency
*
* @param codec
*/
public void changeHandler(JsonCodec codec) {
this.codec = codec;
mapper = codec.mapper;
}
/**
*
* @return the associated codec
*/
public JsonCodec getCodec() {
return codec;
}
/**
*
* @return an empty ObjectNode
*/
public final ObjectNode createObjectNode() {
return mapper.createObjectNode();
}
/**
*
* @return an empty ArrayNode
*/
public final ArrayNode createArrayNode() {
return mapper.createArrayNode();
}
/**
*
* @param value
* @return the objectNode or null if an error occurs
*/
public final ObjectNode getFromString(String value) {
try {
return (ObjectNode) mapper.readTree(value);
} catch (JsonProcessingException e) {
return null;
} catch (IOException e) {
return null;
}
}
/**
*
* @param object
* @return the Json representation of the object
*/
public final String writeAsString(Object object) {
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
return "{}";
}
}
/**
*
* @param node
* @param field
* @return the String if the field exists, else null
*/
public final String getString(ObjectNode node, String field) {
return getValue(node, field, (String) null);
}
/**
*
* @param node
* @param field
* @return the String if the field exists, else null
*/
public final String getString(ObjectNode node, Enum<?> field) {
return getValue(node, field.name(), (String) null);
}
/**
*
* @param node
* @param field
* @param defValue
* @return the String if the field exists, else defValue
*/
public final String getValue(ObjectNode node, String field, String defValue) {
JsonNode elt = node.get(field);
if (elt != null) {
String val = elt.asText();
if (val.equals("null")) {
return defValue;
}
return val;
}
return defValue;
}
/**
*
* @param node
* @param field
* @param defValue
* @return the Boolean if the field exists, else defValue
*/
public final Boolean getValue(ObjectNode node, String field, boolean defValue) {
return node.path(field).asBoolean(defValue);
}
/**
*
* @param node
* @param field
* @param defValue
* @return the Double if the field exists, else defValue
*/
public final Double getValue(ObjectNode node, String field, double defValue) {
return node.path(field).asDouble(defValue);
}
/**
*
* @param node
* @param field
* @param defValue
* @return the Long if the field exists, else defValue
*/
public final Long getValue(ObjectNode node, String field, long defValue) {
return node.path(field).asLong(defValue);
}
/**
*
* @param node
* @param field
* @param defValue
* @return the Integer if the field exists, else defValue
*/
public final Integer getValue(ObjectNode node, String field, int defValue) {
return node.path(field).asInt(defValue);
}
/**
*
* @param node
* @param field
* @param defValue
* @return the byte array if the field exists, else defValue
*/
public final byte[] getValue(ObjectNode node, String field, byte[] defValue) {
JsonNode elt = node.get(field);
if (elt != null) {
try {
return elt.binaryValue();
} catch (IOException e) {
return defValue;
}
}
return defValue;
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, String field, boolean value) {
node.put(field, value);
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, String field, double value) {
node.put(field, value);
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, String field, int value) {
node.put(field, value);
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, String field, long value) {
node.put(field, value);
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, String field, String value) {
if (value == null || value.isEmpty()) {
return;
}
node.put(field, value);
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, String field, byte[] value) {
if (value == null || value.length == 0) {
return;
}
node.put(field, value);
}
/**
*
* @param node
* @param field
* @return True if all fields exist
*/
public final boolean exist(ObjectNode node, String... field) {
for (String string : field) {
if (!node.has(string))
return false;
}
return true;
}
/**
*
* @param node
* @param field
* @param defValue
* @return the String if the field exists, else defValue
*/
public final String getValue(ObjectNode node, Enum<?> field, String defValue) {
return getValue(node, field.name(), defValue);
}
/**
*
* @param node
* @param field
* @param defValue
* @return the Boolean if the field exists, else defValue
*/
public final Boolean getValue(ObjectNode node, Enum<?> field, boolean defValue) {
return node.path(field.name()).asBoolean(defValue);
}
/**
*
* @param node
* @param field
* @param defValue
* @return the Double if the field exists, else defValue
*/
public final Double getValue(ObjectNode node, Enum<?> field, double defValue) {
return node.path(field.name()).asDouble(defValue);
}
/**
*
* @param node
* @param field
* @param defValue
* @return the Long if the field exists, else defValue
*/
public final Long getValue(ObjectNode node, Enum<?> field, long defValue) {
return node.path(field.name()).asLong(defValue);
}
/**
*
* @param node
* @param field
* @param defValue
* @return the Integer if the field exists, else defValue
*/
public final Integer getValue(ObjectNode node, Enum<?> field, int defValue) {
return node.path(field.name()).asInt(defValue);
}
/**
*
* @param node
* @param field
* @param defValue
* @return the byte array if the field exists, else defValue
*/
public final byte[] getValue(ObjectNode node, Enum<?> field, byte[] defValue) {
return getValue(node, field.name(), defValue);
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, Enum<?> field, boolean value) {
node.put(field.name(), value);
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, Enum<?> field, double value) {
node.put(field.name(), value);
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, Enum<?> field, int value) {
node.put(field.name(), value);
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, Enum<?> field, long value) {
node.put(field.name(), value);
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, Enum<?> field, String value) {
if (value == null || value.isEmpty()) {
return;
}
node.put(field.name(), value);
}
/**
*
* @param node
* @param field
* @param value
*/
public final void setValue(ObjectNode node, Enum<?> field, byte[] value) {
if (value == null || value.length == 0) {
return;
}
node.put(field.name(), value);
}
/**
*
* @param node
* @param field
* @return True if all fields exist
*/
public final boolean exist(ObjectNode node, Enum<?>... field) {
for (Enum<?> enm : field) {
if (!node.has(enm.name()))
return false;
}
return true;
}
/**
*
* @param value
* @return the corresponding HashMap
*/
public final Map<String, Object> getMapFromString(String value) {
if (value != null && !value.isEmpty()) {
Map<String, Object> info = null;
try {
info = mapper.readValue(value, new TypeReference<Map<String, Object>>() {});
} catch (JsonParseException e1) {
} catch (JsonMappingException e1) {
} catch (IOException e1) {
}
if (info == null) {
info = new HashMap<String, Object>();
}
return info;
} else {
return new HashMap<String, Object>();
}
}
}