Skip to content

Instantly share code, notes, and snippets.

@letalvoj
Created May 5, 2016 17:47
Show Gist options
  • Save letalvoj/978e6c975398693fc6843c5fe648416d to your computer and use it in GitHub Desktop.
Save letalvoj/978e6c975398693fc6843c5fe648416d to your computer and use it in GitHub Desktop.
Using Jackson together with Spring Data MongoDB
package cz.blindspot.armorway.analytics.configuration;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.mongodb.*;
import com.mongodb.util.JSON;
import org.bson.types.ObjectId;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
@Configuration
@PropertySource(value = "classpath:mongodb.properties")
public class MongoConfiguration extends AbstractMongoConfiguration {
@Value("${mongodb.host}")
private String host;
@Value("${mongodb.db}")
private String databaseName;
@Value("${mongodb.port}")
private int port;
@Value("${mongodb.user}")
private String user;
@Value("${mongodb.passwd}")
private String passwd;
@Override
protected String getDatabaseName() {
return databaseName;
}
@Override
public Mongo mongo() throws Exception {
ServerAddress serverAddress = new ServerAddress(host, port);
List<MongoCredential> credentials = Collections.singletonList(
MongoCredential.createCredential(user, databaseName, passwd.toCharArray())
);
MongoClient mongoClient = new MongoClient(serverAddress, credentials);
return mongoClient;
}
@Override
public MappingMongoConverter mappingMongoConverter() throws Exception {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
ObjectMapper mapper = new ObjectMapper()
.configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(new SimpleModule() {
{
addDeserializer(ObjectId.class, new JsonDeserializer<ObjectId>() {
@Override
public ObjectId deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
TreeNode oid = p.readValueAsTree().get("$oid");
String string = oid.toString().replaceAll("\"", "");
return new ObjectId(string);
}
});
}
});
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext()) {
@Override
public <S> S read(Class<S> clazz, DBObject dbo) {
String string = JSON.serialize(dbo);
try {
return mapper.readValue(string, clazz);
} catch (IOException e) {
throw new RuntimeException(string, e);
}
}
@Override
public void write(Object obj, DBObject dbo) {
String string = null;
try {
string = mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException(string, e);
}
dbo.putAll((DBObject) JSON.parse(string));
}
};
return converter;
}
@Bean
@NotNull
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
@cokeSchlumpf
Copy link

Here an updated implementation which works with the current Spring Data Mongo Version:

{
  // ...
   @Override
    public @NotNull MappingMongoConverter mappingMongoConverter(
        @NotNull MongoDatabaseFactory databaseFactory,
        @NotNull MongoCustomConversions customConversions,
        @NotNull MongoMappingContext mappingContext) {

        var dbRefResolver = new DefaultDbRefResolver(databaseFactory);
        return new MappingMongoConverter(dbRefResolver, mappingContext) {
            @Override
            public void write(@NotNull Object obj, @NotNull Bson bson) {
                var json = Operators.suppressExceptions(
                    () -> om.writeValueAsString(obj),
                    "An exception occurredn while serializing Mongo DB document of type " + obj.getClass()
                        .getName() + "."
                );

                if (bson instanceof Document doc) {
                    doc.putAll(BsonDocument.parse(json));

                    if (doc.containsKey("id")) {
                        doc.put("_id", doc.remove("id"));
                    }
                }
            }

            @Override
            protected <S> @NotNull S readDocument(
                @NotNull ConversionContext context,
                @NotNull Bson bson,
                @NotNull TypeInformation<? extends S> type) {

                if (bson instanceof Document doc) {
                    if (doc.containsKey("_id")) {
                        doc.put("id", doc.remove("_id"));
                    }

                    var json = doc.toJson();

                    return Operators.suppressExceptions(
                        () -> om.readValue(json, type.getType()),
                        "An exception occurredn while de-serializing Mongo DB document of type " + type.getType()
                            .getName() + "."
                    );
                } else {
                    throw new IllegalArgumentException("Expected a Document, got " + bson.getClass().getName() + ".");
                }
            }
        };
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment