/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.avro.util.internal; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.avro.AvroRuntimeException; import org.apache.avro.JsonProperties; import org.apache.avro.Schema; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.util.TokenBuffer; public class JacksonUtils { static final String BYTES_CHARSET = "ISO-8859-1"; private JacksonUtils() { } public static JsonNode toJsonNode(Object datum) { if (datum == null) { return null; } try { TokenBuffer generator = new TokenBuffer(new ObjectMapper()); toJson(datum, generator); return new ObjectMapper().readTree(generator.asParser()); } catch (IOException e) { throw new AvroRuntimeException(e); } } @SuppressWarnings(value="unchecked") static void toJson(Object datum, JsonGenerator generator) throws IOException { if (datum == JsonProperties.NULL_VALUE) { // null generator.writeNull(); } else if (datum instanceof Map) { // record, map generator.writeStartObject(); for (Map.Entry<Object,Object> entry : ((Map<Object,Object>) datum).entrySet()) { generator.writeFieldName(entry.getKey().toString()); toJson(entry.getValue(), generator); } generator.writeEndObject(); } else if (datum instanceof Collection) { // array generator.writeStartArray(); for (Object element : (Collection<?>) datum) { toJson(element, generator); } generator.writeEndArray(); } else if (datum instanceof byte[]) { // bytes, fixed generator.writeString(new String((byte[]) datum, BYTES_CHARSET)); } else if (datum instanceof CharSequence || datum instanceof Enum<?>) { // string, enum generator.writeString(datum.toString()); } else if (datum instanceof Double) { // double generator.writeNumber((Double) datum); } else if (datum instanceof Float) { // float generator.writeNumber((Float) datum); } else if (datum instanceof Long) { // long generator.writeNumber((Long) datum); } else if (datum instanceof Integer) { // int generator.writeNumber((Integer) datum); } else if (datum instanceof Boolean) { // boolean generator.writeBoolean((Boolean) datum); } else { throw new AvroRuntimeException("Unknown datum class: " + datum.getClass()); } } public static Object toObject(JsonNode jsonNode) { return toObject(jsonNode, null); } public static Object toObject(JsonNode jsonNode, Schema schema) { if (schema != null && schema.getType().equals(Schema.Type.UNION)) { return toObject(jsonNode, schema.getTypes().get(0)); } if (jsonNode == null) { return null; } else if (jsonNode.isNull()) { return JsonProperties.NULL_VALUE; } else if (jsonNode.isBoolean()) { return jsonNode.asBoolean(); } else if (jsonNode.isInt()) { if (schema == null || schema.getType().equals(Schema.Type.INT)) { return jsonNode.asInt(); } else if (schema.getType().equals(Schema.Type.LONG)) { return jsonNode.asLong(); } } else if (jsonNode.isLong()) { return jsonNode.asLong(); } else if (jsonNode.isDouble()) { if (schema == null || schema.getType().equals(Schema.Type.DOUBLE)) { return jsonNode.asDouble(); } else if (schema.getType().equals(Schema.Type.FLOAT)) { return (float) jsonNode.asDouble(); } } else if (jsonNode.isTextual()) { if (schema == null || schema.getType().equals(Schema.Type.STRING) || schema.getType().equals(Schema.Type.ENUM)) { return jsonNode.asText(); } else if (schema.getType().equals(Schema.Type.BYTES) || schema.getType().equals(Schema.Type.FIXED)) { try { return jsonNode.getTextValue().getBytes(BYTES_CHARSET); } catch (UnsupportedEncodingException e) { throw new AvroRuntimeException(e); } } } else if (jsonNode.isArray()) { List l = new ArrayList(); for (JsonNode node : jsonNode) { l.add(toObject(node, schema == null ? null : schema.getElementType())); } return l; } else if (jsonNode.isObject()) { Map m = new LinkedHashMap(); for (Iterator<String> it = jsonNode.getFieldNames(); it.hasNext(); ) { String key = it.next(); Schema s = null; if (schema == null) { s = null; } else if (schema.getType().equals(Schema.Type.MAP)) { s = schema.getValueType(); } else if (schema.getType().equals(Schema.Type.RECORD)) { s = schema.getField(key).schema(); } Object value = toObject(jsonNode.get(key), s); m.put(key, value); } return m; } return null; } }