Package org.camunda.spin.impl.json.tree

Source Code of org.camunda.spin.impl.json.tree.JsonJacksonTreeDataFormat

/* 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.camunda.spin.impl.json.tree;

import static org.camunda.spin.impl.util.SpinEnsure.ensureNotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.camunda.spin.impl.json.tree.jsonpath.JsonPathJacksonProvider;
import org.camunda.spin.impl.json.tree.type.DefaultJsonJacksonTypeDetector;
import org.camunda.spin.impl.json.tree.type.ListJsonJacksonTypeDetector;
import org.camunda.spin.json.SpinJsonNode;
import org.camunda.spin.logging.SpinLogger;
import org.camunda.spin.spi.DataFormat;
import org.camunda.spin.spi.DataFormatReader;
import org.camunda.spin.spi.SpinJsonDataFormatException;
import org.camunda.spin.spi.TypeDetector;

import com.fasterxml.jackson.databind.JavaType;
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.databind.type.TypeFactory;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.Configuration.ConfigurationBuilder;
import com.jayway.jsonpath.spi.JsonProvider;

/**
* Spin data format that can wrap Json content and uses
* <a href="http://wiki.fasterxml.com/JacksonHome">Jackson</a> as its implementation.
* Caches an instance of {@link ObjectMapper} as long as configuration does not change
* according to the advice given in the
* <a href="http://wiki.fasterxml.com/JacksonBestPracticesPerformance">Jackson documentation</a>.
*
*
* @author Thorben Lindhauer
* @author Stefan Hentschel
*/
public class JsonJacksonTreeDataFormat implements DataFormat<SpinJsonNode>, JsonJacksonTreeConfigurable {

  public static final JsonJacksonTreeDataFormat INSTANCE = new JsonJacksonTreeDataFormat();
  private static final JsonJacksonTreeLogger LOG = SpinLogger.JSON_TREE_LOGGER;

  protected JsonJacksonParserConfiguration parserConfiguration;
  protected JsonJacksonGeneratorConfiguration generatorConfiguration;
  protected JsonJacksonMapperConfiguration mapperConfiguration;
  protected ObjectMapper cachedObjectMapper;
  protected List<TypeDetector> typeDetectors;

  protected Configuration jsonPathConfiguration;

  public JsonJacksonTreeDataFormat() {
    this.parserConfiguration = new JsonJacksonParserConfiguration(this);
    this.generatorConfiguration = new JsonJacksonGeneratorConfiguration(this);
    this.mapperConfiguration = new JsonJacksonMapperConfiguration(this);

    typeDetectors = new ArrayList<TypeDetector>();
    typeDetectors.add(new ListJsonJacksonTypeDetector());
    typeDetectors.add(new DefaultJsonJacksonTypeDetector());
  }

  public Class<? extends SpinJsonNode> getWrapperType() {
    return SpinJsonJacksonTreeNode.class;
  }

  public SpinJsonNode createWrapperInstance(Object parameter) {
    return new SpinJsonJacksonTreeNode((JsonNode) parameter, this);
  }

  public String getName() {
    return "application/json; implementation=tree";
  }

  // configuration
  public JsonJacksonTreeDataFormat newInstance() {
    JsonJacksonTreeDataFormat instance = new JsonJacksonTreeDataFormat();

    instance.cachedObjectMapper = cachedObjectMapper;

    instance.parserConfiguration =
        new JsonJacksonParserConfiguration(instance, parserConfiguration);
    instance.generatorConfiguration =
        new JsonJacksonGeneratorConfiguration(instance, generatorConfiguration);
    instance.mapperConfiguration =
        new JsonJacksonMapperConfiguration(instance, mapperConfiguration);

    instance.typeDetectors = new ArrayList<TypeDetector>(typeDetectors);

    return instance;
  }

  public DataFormatReader getReader() {
    return new JsonJacksonTreeDataFormatReader(this);
  }

  public JsonJacksonTreeDataFormatMapper getMapper() {
    return new JsonJacksonTreeDataFormatMapper(this);
  }

  public JsonJacksonParserConfiguration reader() {
    return parserConfiguration;
  }

  public JsonJacksonGeneratorConfiguration writer() {
    return generatorConfiguration;
  }

  public JsonJacksonMapperConfiguration mapper() {
    return mapperConfiguration;
  }

  public JsonJacksonTreeDataFormat done() {
    return this;
  }

  public void applyTo(ObjectMapper mapper) {
    parserConfiguration.applyTo(mapper);
    generatorConfiguration.applyTo(mapper);
    mapperConfiguration.applyTo(mapper);
  }

  public ObjectMapper getConfiguredObjectMapper() {
    if (cachedObjectMapper == null) {
      synchronized(this) {
        if (cachedObjectMapper == null) {
          cachedObjectMapper = new ObjectMapper();
          applyTo(cachedObjectMapper);
        }
      }
    }

    return cachedObjectMapper;
  }

  public synchronized void invalidateCachedObjectMapper() {
    cachedObjectMapper = null;
    jsonPathConfiguration = null;
  }

  /**
   * Returns a {@link Configuration} object for jayway json path
   * which uses this dataformat's object mapper as {@link JsonProvider}.
   *
   * @return the {@link Configuration} for jsonpath
   */
  public Configuration getJsonPathConfiguration() {
    if(jsonPathConfiguration == null) {
      jsonPathConfiguration = new ConfigurationBuilder()
        .jsonProvider(new JsonPathJacksonProvider(getConfiguredObjectMapper()))
        .build();
    }
    return jsonPathConfiguration;
  }

  /**
   * Identifies the canonical type of an object heuristically.
   *
   * @return the canonical type identifier of the object's class
   * according to Jackson's type format (see {@link TypeFactory#constructFromCanonical(String)})
   */
  public String getCanonicalTypeName(Object object) {
    ensureNotNull("object", object);

    for (TypeDetector typeDetector : typeDetectors) {
      if (typeDetector.appliesTo(this) && typeDetector.canHandle(object)) {
        return typeDetector.detectType(object);
      }
    }

    throw LOG.unableToDetectCanonicalType(object);
  }

  /**
   * Constructs a {@link JavaType} object based on the parameter, which
   * has to follow Jackson's canonical type string format.
   *
   * @param canonicalString
   * @return
   * @throws SpinJsonDataFormatException if no type can be constructed from the given parameter
   */
  public JavaType constructJavaTypeFromCanonicalString(String canonicalString) {
    try {
      return TypeFactory.defaultInstance().constructFromCanonical(canonicalString);
    } catch (IllegalArgumentException e) {
      throw LOG.unableToConstructJavaType(canonicalString, e);
    }
  }

  public void addTypeDetector(TypeDetector typeDetector) {
    typeDetectors.add(0, typeDetector);
  }

  @SuppressWarnings("unchecked")
  public JsonNode createJsonNode(Object parameter) {
    if(parameter instanceof SpinJsonNode) {
      return (JsonNode) ((SpinJsonNode) parameter).unwrap();

    } else if(parameter instanceof String) {
      return createJsonNode((String) parameter);

    } else if(parameter instanceof Integer) {
      return createJsonNode((Integer) parameter);

    } else if(parameter instanceof Boolean) {
      return createJsonNode((Boolean) parameter);

    } else if(parameter instanceof Float) {
      return createJsonNode((Float) parameter);

    } else if(parameter instanceof Long) {
      return createJsonNode((Long) parameter);

    } else if(parameter instanceof Number) {
      return createJsonNode(((Number) parameter).floatValue());

    } else if(parameter instanceof List) {
      return createJsonNode((List<Object>) parameter);

    } else if(parameter instanceof Map) {
      return createJsonNode((Map<String, Object>) parameter);

    } else {
      throw LOG.unableToCreateNode(parameter.getClass().getSimpleName());
    }
  }

  public JsonNode createJsonNode(String parameter) {
    return getConfiguredObjectMapper().getNodeFactory().textNode(parameter);
  }

  public JsonNode createJsonNode(Integer parameter) {
    return getConfiguredObjectMapper().getNodeFactory().numberNode(parameter);
  }

  public JsonNode createJsonNode(Float parameter) {
    return getConfiguredObjectMapper().getNodeFactory().numberNode(parameter);
  }

  public JsonNode createJsonNode(Long parameter) {
    return getConfiguredObjectMapper().getNodeFactory().numberNode(parameter);
  }

  public JsonNode createJsonNode(Boolean parameter) {
    return getConfiguredObjectMapper().getNodeFactory().booleanNode(parameter);
  }

  public JsonNode createJsonNode(List<Object> parameter) {
    ArrayNode node = getConfiguredObjectMapper().getNodeFactory().arrayNode();
    for(Object entry : parameter) {
      node.add(createJsonNode(entry));
    }
    return node;
  }

  public JsonNode createJsonNode(Map<String, Object> parameter) {
    ObjectNode node = getConfiguredObjectMapper().getNodeFactory().objectNode();
    for (Map.Entry<String, Object> entry : parameter.entrySet()) {
      node.set(entry.getKey(), createJsonNode(entry.getValue()));
    }
    return node;
  }
}
TOP

Related Classes of org.camunda.spin.impl.json.tree.JsonJacksonTreeDataFormat

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.