Package org.springframework.data.couchbase.core.convert.translation

Source Code of org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService

/*
* Copyright 2013 the original author or authors.
*
* 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.springframework.data.couchbase.core.convert.translation;

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.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
import org.springframework.data.couchbase.core.mapping.CouchbaseList;
import org.springframework.data.couchbase.core.mapping.CouchbaseStorable;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.SimpleTypeHolder;

import java.io.*;
import java.util.Map;

/**
* A Jackson JSON Translator that implements the {@link TranslationService} contract.
*
* @author Michael Nitschinger
*/
public class JacksonTranslationService implements TranslationService, InitializingBean {

  /**
   * Jackson Object Mapper;
   */
  private ObjectMapper objectMapper;

  /**
   * Type holder to help easily identify simple types.
   */
  private SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder();

  /**
   * JSON factory for Jackson.
   */
  private JsonFactory factory = new JsonFactory();

  /**
   * Encode a {@link CouchbaseStorable} to a JSON string.
   *
   * @param source the source document to encode.
   *
   * @return the encoded JSON String.
   */
  @Override
  public final Object encode(final CouchbaseStorable source) {
    Writer writer = new StringWriter();

    try {
      JsonGenerator generator = factory.createGenerator(writer);
      encodeRecursive(source, generator);
      generator.close();
      writer.close();
    } catch (IOException ex) {
      throw new RuntimeException("Could not encode JSON", ex);
    }

    return writer.toString();
  }

  /**
   * Recursively iterates through the sources and adds it to the JSON generator.
   *
   * @param source the source document
   * @param generator the JSON generator.
   *
   * @throws IOException
   */
  private void encodeRecursive(final CouchbaseStorable source, final JsonGenerator generator) throws IOException {
    generator.writeStartObject();

    for (Map.Entry<String, Object> entry : ((CouchbaseDocument) source).export().entrySet()) {
      String key = entry.getKey();
      Object value = entry.getValue();
      generator.writeFieldName(key);
      if (value instanceof CouchbaseDocument) {
        encodeRecursive((CouchbaseDocument) value, generator);
        continue;
      }

      final Class<?> clazz = value.getClass();

      if (simpleTypeHolder.isSimpleType(clazz) && !isEnumOrClass(clazz)) {
        generator.writeObject(value);
      } else {
        objectMapper.writeValue(generator, value);
      }

    }

    generator.writeEndObject();
  }

  private boolean isEnumOrClass(final Class<?> clazz) {
    return Enum.class.isAssignableFrom(clazz) || Class.class.isAssignableFrom(clazz);
  }

  /**
   * Decode a JSON string into the {@link CouchbaseStorable} structure.
   *
   * @param source the source formatted document.
   * @param target the target of the populated data.
   *
   * @return the decoded structure.
   */
  @Override
  public final CouchbaseStorable decode(final Object source, final CouchbaseStorable target) {
    try {
      JsonParser parser = factory.createParser((String) source);
      while (parser.nextToken() != null) {
        JsonToken currentToken = parser.getCurrentToken();

        if (currentToken == JsonToken.START_OBJECT) {
          return decodeObject(parser, (CouchbaseDocument) target);
        } else if (currentToken == JsonToken.START_ARRAY) {
          return decodeArray(parser, new CouchbaseList());
        } else {
          throw new MappingException("JSON to decode needs to start as array or object!");
        }
      }
      parser.close();
    } catch (IOException ex) {
      throw new RuntimeException("Could not decode JSON", ex);
    }
    return target;
  }

  /**
   * Helper method to decode an object recursively.
   *
   * @param parser the JSON parser with the content.
   * @param target the target where the content should be stored.
   *
   * @throws IOException
   * @returns the decoded object.
   */
  private CouchbaseDocument decodeObject(final JsonParser parser, final CouchbaseDocument target) throws IOException {
    JsonToken currentToken = parser.nextToken();

    String fieldName = "";
    while (currentToken != null && currentToken != JsonToken.END_OBJECT) {
      if (currentToken == JsonToken.START_OBJECT) {
        target.put(fieldName, decodeObject(parser, new CouchbaseDocument()));
      } else if (currentToken == JsonToken.START_ARRAY) {
        target.put(fieldName, decodeArray(parser, new CouchbaseList()));
      } else if (currentToken == JsonToken.FIELD_NAME) {
        fieldName = parser.getCurrentName();
      } else {
        target.put(fieldName, decodePrimitive(currentToken, parser));
      }

      currentToken = parser.nextToken();
    }

    return target;
  }

  /**
   * Helper method to decode an array recusrively.
   *
   * @param parser the JSON parser with the content.
   * @param target the target where the content should be stored.
   *
   * @throws IOException
   * @returns the decoded list.
   */
  private CouchbaseList decodeArray(final JsonParser parser, final CouchbaseList target) throws IOException {
    JsonToken currentToken = parser.nextToken();

    while (currentToken != null && currentToken != JsonToken.END_ARRAY) {
      if (currentToken == JsonToken.START_OBJECT) {
        target.put(decodeObject(parser, new CouchbaseDocument()));
      } else if (currentToken == JsonToken.START_ARRAY) {
        target.put(decodeArray(parser, new CouchbaseList()));
      } else {
        target.put(decodePrimitive(currentToken, parser));
      }

      currentToken = parser.nextToken();
    }

    return target;
  }

  /**
   * Helper method to decode and assign a primitive.
   *
   * @param token the type of token.
   * @param parser the parser with the content.
   *
   * @return the decoded primitve.
   *
   * @throws IOException
   */
  private Object decodePrimitive(final JsonToken token, final JsonParser parser) throws IOException {
    switch (token) {
      case VALUE_TRUE:
      case VALUE_FALSE:
        return parser.getValueAsBoolean();
      case VALUE_STRING:
        return parser.getValueAsString();
      case VALUE_NUMBER_INT:
        try {
          return parser.getValueAsInt();
        } catch (final JsonParseException e) {
          return parser.getValueAsLong();
        }
      case VALUE_NUMBER_FLOAT:
        return parser.getValueAsDouble();
      case VALUE_NULL:
        return null;
      default:
        throw new MappingException("Could not decode primitve value " + token);
    }
  }

  public void setObjectMapper(final ObjectMapper objectMapper) {
    this.objectMapper = objectMapper;
  }

  @Override
  public void afterPropertiesSet() {
    if (objectMapper == null) {
      objectMapper = new ObjectMapper();
    }
  }

}
TOP

Related Classes of org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService

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.