org.brutusin.json.impl.JacksonCodec.java Source code

Java tutorial

Introduction

Here is the source code for org.brutusin.json.impl.JacksonCodec.java

Source

/*
 * Copyright 2015 brutusin.org
 *
 * Licensed 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.brutusin.json.impl;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.io.JsonStringEncoder;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.databind.type.TypeFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import org.brutusin.commons.Pair;
import org.brutusin.commons.io.MetaDataInputStream;
import org.brutusin.json.spi.JsonNode;
import org.brutusin.json.spi.JsonSchema;
import org.brutusin.json.ParseException;
import org.brutusin.json.impl.serializers.InputStreamDeserializer;
import org.brutusin.json.impl.serializers.InputStreamSerializer;
import org.brutusin.json.impl.serializers.JsonNodeDeserializer;
import org.brutusin.json.impl.serializers.JsonNodeSerializer;
import org.brutusin.json.impl.serializers.SerializationContext;
import org.brutusin.json.spi.JsonCodec;

/**
 * @author Ignacio del Valle Alles idelvall@brutusin.org
 */
public class JacksonCodec extends JsonCodec {

    private static final Map<Class, String> DEFAULT_FORMAT_MAP = new HashMap();

    static {
        DEFAULT_FORMAT_MAP.put(File.class, "file");
        DEFAULT_FORMAT_MAP.put(InputStream.class, "inputstream");
        DEFAULT_FORMAT_MAP.put(MetaDataInputStream.class, "inputstream");
    }

    private final ObjectMapper mapper;
    private final JacksonFactoryWrapper schemaFactory;

    public JacksonCodec() {
        this(null, null);
    }

    public JacksonCodec(ObjectMapper mapper, JacksonFactoryWrapper schemaFactory) {
        if (mapper == null) {
            mapper = new ObjectMapper();

            mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker()
                    .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                    .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                    .withIsGetterVisibility(JsonAutoDetect.Visibility.NONE));

            mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

            SimpleModule testModule = new SimpleModule("json-provider-module",
                    new Version(1, 0, 0, null, "org.brutusin", "json-provider"));
            testModule.addSerializer(new JsonNodeSerializer());
            testModule.addDeserializer(JsonNode.class, new JsonNodeDeserializer());
            testModule.addSerializer(new InputStreamSerializer());
            testModule.addDeserializer(InputStream.class, new InputStreamDeserializer());
            testModule.addDeserializer(MetaDataInputStream.class, new InputStreamDeserializer());
            mapper.registerModule(testModule);
        }
        if (schemaFactory == null) {
            schemaFactory = new JacksonFactoryWrapper(new HashMap<Class, String>(DEFAULT_FORMAT_MAP));
        }
        this.mapper = mapper;
        this.schemaFactory = schemaFactory;
    }

    static String addVersion(String jsonSchema) {
        jsonSchema = jsonSchema.replaceAll("\"\\$schema\"\\s*:\\s*\"[^\"]*\"\\s*,?", "");
        if (!jsonSchema.contains("\"$schema\"")) {
            if (jsonSchema.startsWith("{\"type\":")) {
                StringBuilder sb = new StringBuilder(jsonSchema);
                sb.insert(1, "\"$schema\":\"http://brutusin.org/json/json-schema-spec\",");
                return sb.toString();
            }
        }
        return jsonSchema;
    }

    static String addDraftv3(String jsonSchema) {
        jsonSchema = jsonSchema.replaceAll("\"\\$schema\"\\s*:\\s*\"[^\"]*\"\\s*,?", "");
        if (!jsonSchema.contains("\"$schema\"")) {
            if (jsonSchema.startsWith("{\"type\":")) {
                StringBuilder sb = new StringBuilder(jsonSchema);
                sb.insert(1, "\"$schema\":\"http://json-schema.org/draft-03/schema#\",");
                return sb.toString();
            }
        }
        return jsonSchema;
    }

    @Override
    public void registerStringFormat(Class clazz, String format) {
        this.schemaFactory.registerStringFormat(clazz, format);
        SimpleModule testModule = new SimpleModule("json-provider-module:" + format,
                new Version(1, 0, 0, null, "org.brutusin", "json-provider:" + format));
        testModule.addSerializer(new StdSerializer(clazz) {
            @Override
            public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
                gen.writeString(value.toString());
            }
        });
        mapper.registerModule(testModule);
    }

    @Override
    public String transform(Object o) {
        return transformAndGetSerializationCtx(o).getElement1();
    }

    private Pair<String, Map> transformAndGetSerializationCtx(Object o) {
        try {
            String json = mapper.writeValueAsString(o);
            SerializationContext sCtx = SerializationContext.getCurrentContext();
            return new Pair<String, Map>(json, sCtx == null ? null : sCtx.getMap());
        } catch (JsonProcessingException ex) {
            throw new RuntimeException(ex);
        } finally {
            SerializationContext.closeCurrentContext();
        }
    }

    @Override
    public JsonNode toJsonNode(Object o) {
        Pair<String, Map> pair = transformAndGetSerializationCtx(o);
        try {
            return parse(pair.getElement1(), pair.getElement2());
        } catch (ParseException pe) {
            throw new AssertionError();
        }
    }

    @Override
    public JsonNode parse(String json) throws ParseException {
        return parse(json, (Map) null);
    }

    @Override
    public JsonNode parse(String json, Map<String, InputStream> streams) throws ParseException {
        com.fasterxml.jackson.databind.JsonNode node = load(json);
        return new JacksonNode(node, streams);
    }

    @Override
    public Map<String, InputStream> getStreams(JsonNode node) {
        if (node instanceof JacksonNode) {
            JacksonNode jacksonNode = (JacksonNode) node;
            return jacksonNode.getStreams();
        }
        return null;
    }

    @Override
    public Object parse(String json, Type type) throws ParseException {
        if (json == null || json.trim().isEmpty()) {
            return null;
        }
        try {
            JavaType jt = TypeFactory.defaultInstance().constructType(type);
            return mapper.readValue(json, jt);
        } catch (JsonParseException ex) {
            throw new ParseException(ex);
        } catch (JsonMappingException ex) {
            throw new RuntimeException(ex);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    @Override
    public <T> T parse(String json, Class<T> clazz) throws ParseException {
        if (json == null || json.trim().isEmpty()) {
            return null;
        }
        try {
            return mapper.readValue(json, clazz);
        } catch (JsonParseException ex) {
            throw new ParseException(ex);
        } catch (JsonMappingException ex) {
            throw new RuntimeException(ex);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    public Pair<Object, Integer> parse(String json, Type type, Map<String, InputStream> streams)
            throws ParseException {
        if (json == null || json.trim().isEmpty()) {
            return null;
        }
        try {
            SerializationContext sc = new SerializationContext(streams);
            SerializationContext.setCurrentContext(sc);
            JavaType jt = TypeFactory.defaultInstance().constructType(type);
            return new Pair<Object, Integer>(mapper.readValue(json, jt), sc.getDeclaredStreams());
        } catch (JsonParseException ex) {
            throw new ParseException(ex);
        } catch (JsonMappingException ex) {
            throw new ParseException(ex);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        } finally {
            SerializationContext.closeCurrentContext();
        }
    }

    public <T> Pair<T, Integer> parse(String json, Class<T> clazz, Map<String, InputStream> streams)
            throws ParseException {
        if (json == null || json.trim().isEmpty()) {
            return null;
        }
        try {
            SerializationContext sc = new SerializationContext(streams);
            SerializationContext.setCurrentContext(sc);
            return new Pair<T, Integer>(mapper.readValue(json, clazz), sc.getDeclaredStreams());
        } catch (JsonParseException ex) {
            throw new ParseException(ex);
        } catch (JsonMappingException ex) {
            throw new ParseException(ex);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        } finally {
            SerializationContext.closeCurrentContext();
        }
    }

    @Override
    public <T> T load(JsonNode node, Class<T> clazz) {
        if (node == null) {
            return null;
        }
        if (JsonNode.class.equals(clazz)) {
            return (T) node;
        }
        try {
            Map<String, InputStream> streams;
            if (node instanceof JacksonNode) {
                JacksonNode jn = (JacksonNode) node;
                streams = jn.getStreams();
            } else {
                streams = null;
            }
            return parse(node.toString(), clazz, streams).getElement1();
        } catch (ParseException ex) {
            throw new RuntimeException(ex);
        }
    }

    @Override
    public Object load(JsonNode node, Type type) {
        if (node == null) {
            return null;
        }
        if (JsonNode.class.equals(type)) {
            return node;
        }
        try {
            Map<String, InputStream> streams;
            if (node instanceof JacksonNode) {
                JacksonNode jn = (JacksonNode) node;
                streams = jn.getStreams();
            } else {
                streams = null;
            }
            return parse(node.toString(), type, streams).getElement1();
        } catch (ParseException ex) {
            throw new RuntimeException(ex);
        }
    }

    @Override
    public JsonSchema parseSchema(String json) throws ParseException {
        return new JacksonSchema(json, mapper);
    }

    @Override
    public String getSchemaString(Type type) {
        try {
            mapper.acceptJsonFormatVisitor(mapper.constructType(type), schemaFactory);
            com.fasterxml.jackson.module.jsonSchema.JsonSchema finalSchema = schemaFactory.finalSchema();
            return addVersion(mapper.writeValueAsString(finalSchema));
        } catch (JsonProcessingException ex) {
            throw new RuntimeException(ex);
        }
    }

    @Override
    public String quoteAsUTF8(String s) {
        return new String(JsonStringEncoder.getInstance().quoteAsUTF8(s));
    }

    @Override
    public String prettyPrint(String json) throws ParseException {
        try {
            Object obj = parse(json, Object.class);
            return mapper.writer().withDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (JsonProcessingException ex) {
            throw new ParseException(ex);
        }
    }

    private com.fasterxml.jackson.databind.JsonNode load(String json) throws ParseException {
        if (json == null || json.trim().isEmpty()) {
            return null;
        }
        try {
            return mapper.readTree(json);
        } catch (JsonProcessingException ex) {
            throw new ParseException(ex);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    public static class A extends File {

        public A(String pathname) {
            super(pathname);
        }
    }
}