package com.bbn.bue.common.serialization.jackson;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
import com.google.common.io.ByteSink;
import com.google.common.io.ByteSource;

import java.io.IOException;

import static com.google.common.base.Preconditions.checkNotNull;

public final class JacksonSerializer {

  private final ObjectMapper mapper;

  private JacksonSerializer(ObjectMapper mapper) {
    this.mapper = checkNotNull(mapper);
  }

  private static JacksonSerializer fromJSONFactory(JsonFactory jsonFactory) {
    final ObjectMapper mapper = new ObjectMapper(jsonFactory);
    mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    mapper.findAndRegisterModules();
    return new JacksonSerializer(mapper);
  }

  public static JacksonSerializer forNormalJSON() {
    return fromJSONFactory(new JsonFactory());
  }

  private static JacksonSerializer normalJSONCached;

  public static JacksonSerializer forNormalJSONUncached() {
    if (normalJSONCached == null) {
      normalJSONCached = forNormalJSONUncached();
    }
    return normalJSONCached;
  }

  private static JacksonSerializer smileCached;

  public static JacksonSerializer forSmile() {
    if (smileCached == null) {
      smileCached = forSmileUncached();
    }
    return smileCached;
  }

  public static JacksonSerializer forSmileUncached() {
    return fromJSONFactory(new SmileFactory());
  }


  public void serializeTo(final Object o, final ByteSink out) throws IOException {
    final RootObject rootObj = RootObject.forObject(o);
    mapper.writeValue(out.openBufferedStream(), rootObj);
  }

  public Object deserializeFrom(final ByteSource source) throws IOException {
    final RootObject rootObj = mapper.readValue(source.openStream(), RootObject.class);
    return rootObj.object();
  }

  public String writeValueAsString(Object value) throws JsonProcessingException {
    return mapper.writeValueAsString(value);
  }

  public <T> T deserializeFromString(String content, Class<T> valueType) throws IOException {
    return mapper.readValue(content, valueType);
  }

  private static final class RootObject {

    @JsonCreator
    public RootObject(@JsonProperty("obj") final Object obj) {
      this.obj = checkNotNull(obj);
    }

    public static RootObject forObject(final Object obj) {
      return new RootObject(obj);
    }

    @JsonProperty("obj")
    public Object object() {
      return obj;
    }

    private final Object obj;
  }
}

@@ -309,16 +309,76 @@
 Mapper;%0A
+import com.fasterxml.jackson.databind.SerializationFeature;%0A
 import c
@@ -421,32 +421,32 @@
 e.SmileFactory;%0A
-
 import com.googl
@@ -794,35 +794,36 @@
  static 
-JacksonSerializer f
+ObjectMapper mapperF
 romJSONF
@@ -1041,37 +1041,14 @@
 urn 
-new JacksonSerializer(
 mapper
-)
 ;%0A  
@@ -1117,41 +1117,289 @@
 urn 
-fromJSONFactory(new JsonFactory()
+new JacksonSerializer(mapperFromJSONFactory(new JsonFactory()));%0A  %7D%0A%0A  public static JacksonSerializer forPrettyJSON() %7B%0A    final ObjectMapper ret = mapperFromJSONFactory(new JsonFactory());%0A    ret.enable(SerializationFeature.INDENT_OUTPUT);%0A    return new JacksonSerializer(ret
 );%0A 
@@ -1910,17 +1910,45 @@
  return 
-f
+new JacksonSerializer(mapperF
 romJSONF
@@ -1969,24 +1969,25 @@
 leFactory())
+)
 ;%0A  %7D%0A%0A%0A  pu

Allow creating pretty-printing JSON serializers