Skip to content

Provide JsonNode converter. #1682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,12 @@ public CustomConversions customConversions() {
* @return must not be {@literal null}.
*/
public CustomConversions customConversions(CryptoManager cryptoManager, ObjectMapper objectMapper) {
List<GenericConverter> newConverters = new ArrayList();
List<Object> newConverters = new ArrayList();
// The following
newConverters.add(new OtherConverters.EnumToObject(getObjectMapper()));
newConverters.add(new IntegerToEnumConverterFactory(getObjectMapper()));
newConverters.add(new StringToEnumConverterFactory(getObjectMapper()));
newConverters.add(new BooleanToEnumConverterFactory(getObjectMapper()));
CustomConversions customConversions = CouchbaseCustomConversions.create(configurationAdapter -> {
SimplePropertyValueConversions valueConversions = new SimplePropertyValueConversions();
valueConversions.setConverterFactory(
Expand All @@ -443,10 +448,6 @@ public CustomConversions customConversions(CryptoManager cryptoManager, ObjectMa
valueConversions.afterPropertiesSet(); // wraps the CouchbasePropertyValueConverterFactory with CachingPVCFactory
configurationAdapter.setPropertyValueConversions(valueConversions);
configurationAdapter.registerConverters(newConverters);
configurationAdapter.registerConverter(new OtherConverters.EnumToObject(getObjectMapper()));
configurationAdapter.registerConverterFactory(new IntegerToEnumConverterFactory(getObjectMapper()));
configurationAdapter.registerConverterFactory(new StringToEnumConverterFactory(getObjectMapper()));
configurationAdapter.registerConverterFactory(new BooleanToEnumConverterFactory(getObjectMapper()));
});
return customConversions;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,23 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import com.couchbase.client.java.json.JsonArray;
import com.couchbase.client.java.json.JsonObject;
import com.couchbase.client.java.json.JsonValueModule;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
import org.springframework.data.couchbase.core.mapping.CouchbaseList;
import org.springframework.util.Base64Utils;

import com.couchbase.client.core.encryption.CryptoManager;
Expand Down Expand Up @@ -66,6 +77,12 @@ private OtherConverters() {}
converters.add(StringToCharArray.INSTANCE);
converters.add(ClassToString.INSTANCE);
converters.add(StringToClass.INSTANCE);
converters.add(MapToJsonNode.INSTANCE);
converters.add(JsonNodeToMap.INSTANCE);
converters.add(JsonObjectToMap.INSTANCE);
converters.add(MapToJsonObject.INSTANCE);
converters.add(JsonArrayToCouchbaseList.INSTANCE);
converters.add(CouchbaseListToJsonArray.INSTANCE);
// EnumToObject, IntegerToEnumConverterFactory and StringToEnumConverterFactory are
// registered in
// {@link org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration#customConversions(
Expand Down Expand Up @@ -231,4 +248,85 @@ public Object convert(Enum<?> source) {
}
}

@WritingConverter
public enum JsonNodeToMap implements Converter<JsonNode, CouchbaseDocument> {
INSTANCE;
static ObjectMapper mapper= new ObjectMapper().registerModule(new JsonValueModule());
@Override
public CouchbaseDocument convert(JsonNode source) {
if( source == null ){
return null;
}
return new CouchbaseDocument().setContent((Map)mapper.convertValue(source, new TypeReference<Map<String, Object>>(){}));
}
}

@ReadingConverter
public enum MapToJsonNode implements Converter<CouchbaseDocument, JsonNode> {
INSTANCE;
static ObjectMapper mapper= new ObjectMapper().registerModule(new JsonValueModule());

@Override
public JsonNode convert(CouchbaseDocument source) {
if( source == null ){
return null;
}
return mapper.valueToTree(source.export());
}
}

@WritingConverter
public enum JsonObjectToMap implements Converter<JsonObject, CouchbaseDocument> {
INSTANCE;

@Override
public CouchbaseDocument convert(JsonObject source) {
if( source == null ){
return null;
}
return new CouchbaseDocument().setContent(source);
}
}

@ReadingConverter
public enum MapToJsonObject implements Converter<CouchbaseDocument, JsonObject> {
INSTANCE;
static ObjectMapper mapper= new ObjectMapper();

@Override
public JsonObject convert(CouchbaseDocument source) {
if( source == null ){
return null;
}
return JsonObject.from(source.export());
}
}

@WritingConverter
public enum JsonArrayToCouchbaseList implements Converter<JsonArray, CouchbaseList> {
INSTANCE;

@Override
public CouchbaseList convert(JsonArray source) {
if( source == null ){
return null;
}
return new CouchbaseList(source.toList());
}
}

@ReadingConverter
public enum CouchbaseListToJsonArray implements Converter<CouchbaseList, JsonArray> {
INSTANCE;
static ObjectMapper mapper= new ObjectMapper();

@Override
public JsonArray convert(CouchbaseList source) {
if( source == null ){
return null;
}
return JsonArray.from(source.export());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ void findByIdWithExpiry() {
assertEquals(1, foundUsers.size(), "should have found exactly 1 user");
assertEquals(user2, foundUsers.iterator().next());
} finally {
couchbaseTemplate.removeByQuery(User.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
//couchbaseTemplate.removeByQuery(User.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}

}
Expand Down Expand Up @@ -1046,6 +1046,13 @@ void insertById() {
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
User inserted = couchbaseTemplate.insertById(User.class).one(user);
assertEquals(user, inserted);
User found = couchbaseTemplate.findById(User.class).one(user.getId());
assertEquals(inserted, found);
System.err.println("inserted: "+inserted);
System.err.println("found: "+found);
System.err.println("found:jsonNode "+found.jsonNode.toPrettyString());
System.err.println("found:jsonObject "+found.jsonObject.toString());
System.err.println("found:jsonArray "+found.jsonArray.toString());
assertThrows(DuplicateKeyException.class, () -> couchbaseTemplate.insertById(User.class).one(user));
couchbaseTemplate.removeById(User.class).one(user.getId());
}
Expand Down
29 changes: 29 additions & 0 deletions src/test/java/org/springframework/data/couchbase/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@
package org.springframework.data.couchbase.domain;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import com.couchbase.client.java.json.JsonArray;
import com.couchbase.client.java.json.JsonObject;
import com.couchbase.client.java.json.JsonValue;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
Expand All @@ -29,6 +34,10 @@
import org.springframework.data.annotation.Version;
import org.springframework.data.couchbase.core.mapping.Document;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
* User entity for tests
*
Expand All @@ -40,14 +49,34 @@
@TypeAlias(AbstractingTypeMapper.Type.ABSTRACTUSER)
public class User extends AbstractUser implements Serializable {

public JsonNode jsonNode;
public JsonObject jsonObject;
public JsonArray jsonArray;

@PersistenceConstructor
public User(final String id, final String firstname, final String lastname) {
this.id = id;
this.firstname = firstname;
this.lastname = lastname;
this.subtype = AbstractingTypeMapper.Type.USER;
this.jsonNode = new ObjectNode(JsonNodeFactory.instance);
try {
jsonNode = (new ObjectNode(JsonNodeFactory.instance)).put("myNumber", uid());
} catch (Exception e) {
e.printStackTrace();
}
Map map = new HashMap();
map.put("myNumber", uid());
this.jsonObject = JsonObject.jo().put("yourNumber",Long.valueOf(uid()));
this.jsonArray = JsonArray.from(Long.valueOf(uid()), Long.valueOf(uid()));
}

@Transient int uid=1000;
long uid(){
return uid++;
}


@Version protected long version;
@Transient protected String transientInfo;
@CreatedBy protected String createdBy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ void createsQueryCorrectly() throws Exception {

Query query = creator.createQuery();
assertEquals(
"SELECT `_class`, META(`" + bucketName()
"SELECT `_class`, `jsonNode`, `jsonObject`, `jsonArray`, META(`" + bucketName()
+ "`).`cas` AS __cas, `createdBy`, `createdDate`, `lastModifiedBy`, `lastModifiedDate`, META(`"
+ bucketName() + "`).`id` AS __id, `firstname`, `lastname`, `subtype` FROM `" + bucketName()
+ "` where `_class` = \"abstractuser\" and firstname = $1 and lastname = $2",
Expand All @@ -131,7 +131,7 @@ void createsQueryCorrectly2() throws Exception {

Query query = creator.createQuery();
assertEquals(
"SELECT `_class`, META(`" + bucketName()
"SELECT `_class`, `jsonNode`, `jsonObject`, `jsonArray`, META(`" + bucketName()
+ "`).`cas` AS __cas, `createdBy`, `createdDate`, `lastModifiedBy`, `lastModifiedDate`, META(`"
+ bucketName() + "`).`id` AS __id, `firstname`, `lastname`, `subtype` FROM `" + bucketName()
+ "` where `_class` = \"abstractuser\" and (firstname = $first or lastname = $last)",
Expand All @@ -151,11 +151,9 @@ void spelTests() throws Exception {

Query query = creator.createQuery();

assertEquals(
"SELECT `_class`, META(`myCollection`).`cas` AS __cas, `createdBy`, `createdDate`, "
+ "`lastModifiedBy`, `lastModifiedDate`, META(`myCollection`).`id` AS __id, `firstname`, "
+ "`lastname`, `subtype` FROM `myCollection`|`_class` = \"abstractuser\""
+ "|`myCollection`|`myScope`|`myCollection`",
assertEquals("SELECT `_class`, `jsonNode`, `jsonObject`, `jsonArray`, META(`myCollection`).`cas`"
+ " AS __cas, `createdBy`, `createdDate`, `lastModifiedBy`, `lastModifiedDate`, META(`myCollection`).`id`"
+ " AS __id, `firstname`, `lastname`, `subtype` FROM `myCollection`|`_class` = \"abstractuser\"|`myCollection`|`myScope`|`myCollection`",
query.toN1qlSelectString(converter, bucketName(), "myScope", "myCollection", User.class, null, false, null,
null));
}
Expand Down