Add Converters for JsonNode, JsonObject and JsonArray. (#1682)
Closes #1650.
This commit is contained in:
@@ -434,7 +434,12 @@ public abstract class AbstractCouchbaseConfiguration {
|
||||
* @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(
|
||||
@@ -443,10 +448,6 @@ public abstract class AbstractCouchbaseConfiguration {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -24,12 +24,23 @@ import java.math.BigInteger;
|
||||
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;
|
||||
@@ -66,6 +77,12 @@ public final class 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(
|
||||
@@ -231,4 +248,85 @@ public final class OtherConverters {
|
||||
}
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ class CouchbaseTemplateKeyValueIntegrationTests extends JavaIntegrationTests {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1046,6 +1046,13 @@ class CouchbaseTemplateKeyValueIntegrationTests extends JavaIntegrationTests {
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -29,6 +34,10 @@ import org.springframework.data.annotation.TypeAlias;
|
||||
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
|
||||
*
|
||||
@@ -40,14 +49,34 @@ import org.springframework.data.couchbase.core.mapping.Document;
|
||||
@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;
|
||||
|
||||
@@ -110,7 +110,7 @@ class StringN1qlQueryCreatorTests {
|
||||
|
||||
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",
|
||||
@@ -131,7 +131,7 @@ class StringN1qlQueryCreatorTests {
|
||||
|
||||
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)",
|
||||
@@ -151,11 +151,9 @@ class StringN1qlQueryCreatorTests {
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user