org.jberet.support.io.MappingJsonFactoryObjectFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.jberet.support.io.MappingJsonFactoryObjectFactory.java

Source

/*
 * Copyright (c) 2014-2015 Red Hat, Inc. and/or its affiliates.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Cheng Fang - Initial API and implementation
 */

package org.jberet.support.io;

import java.util.Hashtable;
import java.util.StringTokenizer;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.MappingJsonFactory;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.jberet.support._private.SupportMessages;

/**
 * An implementation of {@code javax.naming.spi.ObjectFactory} that produces instance of
 * {@code com.fasterxml.jackson.databind.MappingJsonFactory}. This class can be used to create a custom JNDI resource
 * in an application server. See wildfly.home/docs/schema/jboss-as-naming_2_0.xsd for more details.
 *
 * @see "javax.naming.spi.ObjectFactory"
 * @see "wildfly.home/docs/schema/jboss-as-naming_2_0.xsd"
 * @since 1.0.2
 */
public final class MappingJsonFactoryObjectFactory implements ObjectFactory {
    private volatile MappingJsonFactory jsonFactoryCached;

    /**
     * Gets an instance of {@code com.fasterxml.jackson.databind.MappingJsonFactory} based on the resource configuration
     * in the application server. The parameter {@code environment} contains MappingJsonFactory configuration properties,
     * and accepts the following properties:
     * <ul>
     * <li>jsonFactoryFeatures: JsonFactory features as defined in com.fasterxml.jackson.core.JsonFactory.Feature
     * <li>mapperFeatures: ObjectMapper features as defined in com.fasterxml.jackson.databind.MapperFeature
     * <li>deserializationFeatures:
     * <li>serializationFeatures:
     * <li>customDeserializers:
     * <li>customSerializers:
     * <li>deserializationProblemHandlers:
     * <li>customDataTypeModules:
     * <li>inputDecorator: fully-qualified name of a class that extends {@code com.fasterxml.jackson.core.io.InputDecorator}
     * <li>outputDecorator: fully-qualified name of a class that extends {@code com.fasterxml.jackson.core.io.OutputDecorator}
     * </ul>
     *
     * @param obj         the JNDI name of {@code com.fasterxml.jackson.databind.MappingJsonFactory} resource
     * @param name        always null
     * @param nameCtx     always null
     * @param environment a {@code Hashtable} of configuration properties
     * @return an instance of {@code com.fasterxml.jackson.databind.MappingJsonFactory}
     * @throws Exception any exception occurred
     */
    @Override
    public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx,
            final Hashtable<?, ?> environment) throws Exception {
        MappingJsonFactory jsonFactory = jsonFactoryCached;
        if (jsonFactory == null) {
            synchronized (this) {
                jsonFactory = jsonFactoryCached;
                if (jsonFactory == null) {
                    jsonFactoryCached = jsonFactory = new MappingJsonFactory();
                }

                final ClassLoader classLoader = MappingJsonFactoryObjectFactory.class.getClassLoader();
                final ObjectMapper objectMapper = jsonFactory.getCodec();

                final Object jsonFactoryFeatures = environment.get("jsonFactoryFeatures");
                if (jsonFactoryFeatures != null) {
                    NoMappingJsonFactoryObjectFactory.configureJsonFactoryFeatures(jsonFactory,
                            (String) jsonFactoryFeatures);
                }

                final Object mapperFeatures = environment.get("mapperFeatures");
                if (mapperFeatures != null) {
                    configureMapperFeatures(objectMapper, (String) mapperFeatures);
                }

                final Object deserializationFeatures = environment.get("deserializationFeatures");
                if (deserializationFeatures != null) {
                    configureDeserializationFeatures(objectMapper, (String) deserializationFeatures);
                }

                final Object serializationFeatures = environment.get("serializationFeatures");
                if (serializationFeatures != null) {
                    configureSerializationFeatures(objectMapper, (String) serializationFeatures);
                }

                final Object deserializationProblemHandlers = environment.get("deserializationProblemHandlers");
                if (deserializationProblemHandlers != null) {
                    configureDeserializationProblemHandlers(objectMapper, (String) deserializationProblemHandlers,
                            classLoader);
                }

                configureCustomSerializersAndDeserializers(objectMapper,
                        (String) environment.get("customSerializers"),
                        (String) environment.get("customDeserializers"),
                        (String) environment.get("customDataTypeModules"), classLoader);
                NoMappingJsonFactoryObjectFactory.configureInputDecoratorAndOutputDecorator(jsonFactory,
                        environment);
            }
        }
        return jsonFactory;
    }

    static void configureDeserializationProblemHandlers(final ObjectMapper objectMapper,
            final String deserializationProblemHandlers, final ClassLoader classLoader) throws Exception {
        final StringTokenizer st = new StringTokenizer(deserializationProblemHandlers, ", ");
        while (st.hasMoreTokens()) {
            final Class<?> c = classLoader.loadClass(st.nextToken());
            objectMapper.addHandler((DeserializationProblemHandler) c.newInstance());
        }
    }

    static void configureCustomSerializersAndDeserializers(final ObjectMapper objectMapper,
            final String customSerializers, final String customDeserializers, final String customDataTypeModules,
            final ClassLoader classLoader) throws Exception {
        if (customDeserializers != null || customSerializers != null) {
            final SimpleModule simpleModule = new SimpleModule("custom-serializer-deserializer-module");
            if (customSerializers != null) {
                final StringTokenizer st = new StringTokenizer(customSerializers, ", ");
                while (st.hasMoreTokens()) {
                    final Class<?> aClass = classLoader.loadClass(st.nextToken());
                    simpleModule.addSerializer(aClass, (JsonSerializer) aClass.newInstance());
                }
            }
            if (customDeserializers != null) {
                final StringTokenizer st = new StringTokenizer(customDeserializers, ", ");
                while (st.hasMoreTokens()) {
                    final Class<?> aClass = classLoader.loadClass(st.nextToken());
                    simpleModule.addDeserializer(aClass, (JsonDeserializer) aClass.newInstance());
                }
            }
            objectMapper.registerModule(simpleModule);
        }
        if (customDataTypeModules != null) {
            final StringTokenizer st = new StringTokenizer(customDataTypeModules, ", ");
            while (st.hasMoreTokens()) {
                final Class<?> aClass = classLoader.loadClass(st.nextToken());
                objectMapper.registerModule((Module) aClass.newInstance());
            }
        }
    }

    static void configureMapperFeatures(final ObjectMapper objectMapper, final String features) {
        final StringTokenizer st = new StringTokenizer(features, ",");
        while (st.hasMoreTokens()) {
            final String[] pair = NoMappingJsonFactoryObjectFactory.parseSingleFeatureValue(st.nextToken().trim());
            final String key = pair[0];
            final String value = pair[1];

            final MapperFeature feature;
            try {
                feature = MapperFeature.valueOf(key);
            } catch (final Exception e1) {
                throw SupportMessages.MESSAGES.unrecognizedReaderWriterProperty(key, value);
            }
            if ("true".equals(value)) {
                if (!feature.enabledByDefault()) {
                    objectMapper.configure(feature, true);
                }
            } else if ("false".equals(value)) {
                if (feature.enabledByDefault()) {
                    objectMapper.configure(feature, false);
                }
            } else {
                throw SupportMessages.MESSAGES.invalidReaderWriterProperty(null, value, key);
            }
        }
    }

    static void configureSerializationFeatures(final ObjectMapper objectMapper, final String features) {
        final StringTokenizer st = new StringTokenizer(features, ",");
        while (st.hasMoreTokens()) {
            final String[] pair = NoMappingJsonFactoryObjectFactory.parseSingleFeatureValue(st.nextToken().trim());
            final String key = pair[0];
            final String value = pair[1];

            final SerializationFeature feature;
            try {
                feature = SerializationFeature.valueOf(key);
            } catch (final Exception e1) {
                throw SupportMessages.MESSAGES.unrecognizedReaderWriterProperty(key, value);
            }
            if ("true".equals(value)) {
                if (!feature.enabledByDefault()) {
                    objectMapper.configure(feature, true);
                }
            } else if ("false".equals(value)) {
                if (feature.enabledByDefault()) {
                    objectMapper.configure(feature, false);
                }
            } else {
                throw SupportMessages.MESSAGES.invalidReaderWriterProperty(null, value, key);
            }
        }
    }

    static void configureDeserializationFeatures(final ObjectMapper objectMapper, final String features) {
        final StringTokenizer st = new StringTokenizer(features, ",");
        while (st.hasMoreTokens()) {
            final String[] pair = NoMappingJsonFactoryObjectFactory.parseSingleFeatureValue(st.nextToken().trim());
            final String key = pair[0];
            final String value = pair[1];

            final DeserializationFeature feature;
            try {
                feature = DeserializationFeature.valueOf(key);
            } catch (final Exception e1) {
                throw SupportMessages.MESSAGES.unrecognizedReaderWriterProperty(key, value);
            }
            if ("true".equals(value)) {
                if (!feature.enabledByDefault()) {
                    objectMapper.configure(feature, true);
                }
            } else if ("false".equals(value)) {
                if (feature.enabledByDefault()) {
                    objectMapper.configure(feature, false);
                }
            } else {
                throw SupportMessages.MESSAGES.invalidReaderWriterProperty(null, value, key);
            }
        }
    }
}