Skip to content

Instantly share code, notes, and snippets.

@chrisirhc
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisirhc/9651004 to your computer and use it in GitHub Desktop.
Save chrisirhc/9651004 to your computer and use it in GitHub Desktop.
MongoIdModule
package com.example.db.mongo;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
// Override the serializer for ObjectId annotation
public @interface MongoId {
}
package com.example.db.mongo;
import java.lang.reflect.Field;
import org.jongo.marshall.jackson.JacksonIdFieldSelector;
/**
* Extend JacksonIdFieldSelector to look for MongoId objects so that
* updating the ID of the object after saving it works
*
* @see org.jongo.marshall.jackson.JacksonMapper.Builder#withObjectIdUpdater(org.jongo.ObjectIdUpdater)
*/
public class MongoIdFieldSelector extends JacksonIdFieldSelector {
@Override
public boolean isId(Field f) {
return hasIdAnnotation(f) || super.isId(f);
}
private boolean hasIdAnnotation(Field f) {
return f.getAnnotation(MongoId.class) != null;
}
}
package com.example.db.mongo;
import java.util.List;
import org.jongo.ReflectiveObjectIdUpdater;
import org.jongo.marshall.jackson.JacksonMapper;
import org.jongo.marshall.jackson.configuration.MapperModifier;
import org.jongo.marshall.jackson.oid.ObjectIdDeserializer;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.util.NameTransformer;
/**
* Module to convert to and from
*/
public class MongoIdModule extends SimpleModule {
@Override
public void setupModule(SetupContext context) {
context.addBeanSerializerModifier(new SerializerModifier());
context.addBeanDeserializerModifier(new DeserializerModifier());
}
public static class SerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
for (int i = 0; i < beanProperties.size(); i++) {
BeanPropertyWriter beanPropertyWriter = beanProperties.get(i);
MongoId annotation = beanPropertyWriter.getAnnotation(MongoId.class);
if (annotation != null) {
BeanPropertyWriter beanPropertyWriterRenamed = beanPropertyWriter.rename(new ToIdTransformer(beanPropertyWriter.getName()));
if (beanPropertyWriter.getPropertyType().equals(String.class)) {
beanPropertyWriterRenamed.assignSerializer(new MongoIdSerializer());
}
beanProperties.set(i, beanPropertyWriterRenamed);
}
}
return beanProperties;
}
}
public static class DeserializerModifier extends BeanDeserializerModifier {
JsonDeserialize deserializeAnnotation;
@JsonDeserialize(using = ObjectIdDeserializer.class)
private static class DeserializeUsingObjectId {}
public DeserializerModifier() {
deserializeAnnotation = DeserializeUsingObjectId.class.getAnnotation(JsonDeserialize.class);
}
@Override
public List<BeanPropertyDefinition> updateProperties(DeserializationConfig config, BeanDescription beanDesc, List<BeanPropertyDefinition> propDefs) {
for (int i = 0; i < propDefs.size(); i++) {
BeanPropertyDefinition propertyDefinition = propDefs.get(i);
AnnotatedField field = propertyDefinition.getField();
if (field != null && field.hasAnnotation(MongoId.class)) {
field.addIfNotPresent(deserializeAnnotation);
propDefs.set(i, propertyDefinition.withName("_id"));
}
}
return propDefs;
}
}
public static class ToIdTransformer extends NameTransformer {
private static final String ID_FIELD = "_id";
private String originalName;
public ToIdTransformer(String originalName) {
this.originalName = originalName;
}
@Override
public String reverse(String transformed) {
return originalName;
}
@Override
public String transform(String name) {
return ID_FIELD;
}
}
public static class MapperModder implements MapperModifier {
@Override
public void modify(ObjectMapper mapper) {
mapper.registerModule(new MongoIdModule());
}
}
/**
* Use this for JacksonMapper setup
*/
public static JacksonMapper.Builder getMapperBuilder() {
return new JacksonMapper.Builder()
.addModifier(new MongoModule.MapperModder())
.withObjectIdUpdater(new ReflectiveObjectIdUpdater(new MongoIdFieldSelector()));
}
}
package com.example.db.mongo;
import java.io.IOException;
import org.jongo.marshall.jackson.oid.ObjectIdSerializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
/**
* Wrapper for ObjectIdSerializer so that it can be applied on generic objects
*/
public class MongoIdSerializer extends JsonSerializer<Object> {
private static ObjectIdSerializer objectIdSerializer = new ObjectIdSerializer();
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
objectIdSerializer.serialize((String) value, jgen, provider);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment