Skip to content

Commit 3c8d487

Browse files
committed
Add Converters for JsonNode, JsonObject and JsonArray.
Closes #1650.
1 parent 0e76118 commit 3c8d487

File tree

5 files changed

+146
-13
lines changed

5 files changed

+146
-13
lines changed

Diff for: src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,12 @@ public CustomConversions customConversions() {
415415
* @return must not be {@literal null}.
416416
*/
417417
public CustomConversions customConversions(CryptoManager cryptoManager, ObjectMapper objectMapper) {
418-
List<GenericConverter> newConverters = new ArrayList();
418+
List<Object> newConverters = new ArrayList();
419+
// The following
420+
newConverters.add(new OtherConverters.EnumToObject(getObjectMapper()));
421+
newConverters.add(new IntegerToEnumConverterFactory(getObjectMapper()));
422+
newConverters.add(new StringToEnumConverterFactory(getObjectMapper()));
423+
newConverters.add(new BooleanToEnumConverterFactory(getObjectMapper()));
419424
CustomConversions customConversions = CouchbaseCustomConversions.create(configurationAdapter -> {
420425
SimplePropertyValueConversions valueConversions = new SimplePropertyValueConversions();
421426
valueConversions.setConverterFactory(
@@ -424,10 +429,6 @@ public CustomConversions customConversions(CryptoManager cryptoManager, ObjectMa
424429
valueConversions.afterPropertiesSet(); // wraps the CouchbasePropertyValueConverterFactory with CachingPVCFactory
425430
configurationAdapter.setPropertyValueConversions(valueConversions);
426431
configurationAdapter.registerConverters(newConverters);
427-
configurationAdapter.registerConverter(new OtherConverters.EnumToObject(getObjectMapper()));
428-
configurationAdapter.registerConverterFactory(new IntegerToEnumConverterFactory(getObjectMapper()));
429-
configurationAdapter.registerConverterFactory(new StringToEnumConverterFactory(getObjectMapper()));
430-
configurationAdapter.registerConverterFactory(new BooleanToEnumConverterFactory(getObjectMapper()));
431432
});
432433
return customConversions;
433434
}

Diff for: src/main/java/org/springframework/data/couchbase/core/convert/OtherConverters.java

+98
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,23 @@
2424
import java.nio.charset.StandardCharsets;
2525
import java.util.ArrayList;
2626
import java.util.Collection;
27+
import java.util.HashMap;
2728
import java.util.List;
29+
import java.util.Map;
2830
import java.util.UUID;
2931

32+
import com.couchbase.client.java.json.JsonArray;
33+
import com.couchbase.client.java.json.JsonObject;
34+
import com.couchbase.client.java.json.JsonValueModule;
35+
import com.fasterxml.jackson.core.type.TypeReference;
36+
import com.fasterxml.jackson.databind.JsonNode;
37+
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
38+
import com.fasterxml.jackson.databind.node.ObjectNode;
3039
import org.springframework.core.convert.converter.Converter;
3140
import org.springframework.data.convert.ReadingConverter;
3241
import org.springframework.data.convert.WritingConverter;
42+
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
43+
import org.springframework.data.couchbase.core.mapping.CouchbaseList;
3344
import org.springframework.util.Base64Utils;
3445

3546
import com.couchbase.client.core.encryption.CryptoManager;
@@ -66,6 +77,12 @@ private OtherConverters() {}
6677
converters.add(StringToCharArray.INSTANCE);
6778
converters.add(ClassToString.INSTANCE);
6879
converters.add(StringToClass.INSTANCE);
80+
converters.add(MapToJsonNode.INSTANCE);
81+
converters.add(JsonNodeToMap.INSTANCE);
82+
converters.add(JsonObjectToMap.INSTANCE);
83+
converters.add(MapToJsonObject.INSTANCE);
84+
converters.add(JsonArrayToCouchbaseList.INSTANCE);
85+
converters.add(CouchbaseListToJsonArray.INSTANCE);
6986
// EnumToObject, IntegerToEnumConverterFactory and StringToEnumConverterFactory are
7087
// registered in
7188
// {@link org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration#customConversions(
@@ -231,4 +248,85 @@ public Object convert(Enum<?> source) {
231248
}
232249
}
233250

251+
@WritingConverter
252+
public enum JsonNodeToMap implements Converter<JsonNode, CouchbaseDocument> {
253+
INSTANCE;
254+
static ObjectMapper mapper= new ObjectMapper().registerModule(new JsonValueModule());
255+
@Override
256+
public CouchbaseDocument convert(JsonNode source) {
257+
if( source == null ){
258+
return null;
259+
}
260+
return new CouchbaseDocument().setContent((Map)mapper.convertValue(source, new TypeReference<Map<String, Object>>(){}));
261+
}
262+
}
263+
264+
@ReadingConverter
265+
public enum MapToJsonNode implements Converter<CouchbaseDocument, JsonNode> {
266+
INSTANCE;
267+
static ObjectMapper mapper= new ObjectMapper().registerModule(new JsonValueModule());
268+
269+
@Override
270+
public JsonNode convert(CouchbaseDocument source) {
271+
if( source == null ){
272+
return null;
273+
}
274+
return mapper.valueToTree(source.export());
275+
}
276+
}
277+
278+
@WritingConverter
279+
public enum JsonObjectToMap implements Converter<JsonObject, CouchbaseDocument> {
280+
INSTANCE;
281+
282+
@Override
283+
public CouchbaseDocument convert(JsonObject source) {
284+
if( source == null ){
285+
return null;
286+
}
287+
return new CouchbaseDocument().setContent(source);
288+
}
289+
}
290+
291+
@ReadingConverter
292+
public enum MapToJsonObject implements Converter<CouchbaseDocument, JsonObject> {
293+
INSTANCE;
294+
static ObjectMapper mapper= new ObjectMapper();
295+
296+
@Override
297+
public JsonObject convert(CouchbaseDocument source) {
298+
if( source == null ){
299+
return null;
300+
}
301+
return JsonObject.from(source.export());
302+
}
303+
}
304+
305+
@WritingConverter
306+
public enum JsonArrayToCouchbaseList implements Converter<JsonArray, CouchbaseList> {
307+
INSTANCE;
308+
309+
@Override
310+
public CouchbaseList convert(JsonArray source) {
311+
if( source == null ){
312+
return null;
313+
}
314+
return new CouchbaseList(source.toList());
315+
}
316+
}
317+
318+
@ReadingConverter
319+
public enum CouchbaseListToJsonArray implements Converter<CouchbaseList, JsonArray> {
320+
INSTANCE;
321+
static ObjectMapper mapper= new ObjectMapper();
322+
323+
@Override
324+
public JsonArray convert(CouchbaseList source) {
325+
if( source == null ){
326+
return null;
327+
}
328+
return JsonArray.from(source.export());
329+
}
330+
}
331+
234332
}

Diff for: src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateKeyValueIntegrationTests.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ void findByIdWithExpiry() {
114114
assertEquals(1, foundUsers.size(), "should have found exactly 1 user");
115115
assertEquals(user2, foundUsers.iterator().next());
116116
} finally {
117-
couchbaseTemplate.removeByQuery(User.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
117+
//couchbaseTemplate.removeByQuery(User.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
118118
}
119119

120120
}
@@ -445,6 +445,13 @@ void insertById() {
445445
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
446446
User inserted = couchbaseTemplate.insertById(User.class).one(user);
447447
assertEquals(user, inserted);
448+
User found = couchbaseTemplate.findById(User.class).one(user.getId());
449+
assertEquals(inserted, found);
450+
System.err.println("inserted: "+inserted);
451+
System.err.println("found: "+found);
452+
System.err.println("found:jsonNode "+found.jsonNode.toPrettyString());
453+
System.err.println("found:jsonObject "+found.jsonObject.toString());
454+
System.err.println("found:jsonArray "+found.jsonArray.toString());
448455
assertThrows(DuplicateKeyException.class, () -> couchbaseTemplate.insertById(User.class).one(user));
449456
couchbaseTemplate.removeById(User.class).one(user.getId());
450457
}

Diff for: src/test/java/org/springframework/data/couchbase/domain/User.java

+29
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,13 @@
1717
package org.springframework.data.couchbase.domain;
1818

1919
import java.io.Serializable;
20+
import java.util.HashMap;
21+
import java.util.Map;
2022
import java.util.Objects;
2123

24+
import com.couchbase.client.java.json.JsonArray;
25+
import com.couchbase.client.java.json.JsonObject;
26+
import com.couchbase.client.java.json.JsonValue;
2227
import org.springframework.data.annotation.CreatedBy;
2328
import org.springframework.data.annotation.CreatedDate;
2429
import org.springframework.data.annotation.LastModifiedBy;
@@ -29,6 +34,10 @@
2934
import org.springframework.data.annotation.Version;
3035
import org.springframework.data.couchbase.core.mapping.Document;
3136

37+
import com.fasterxml.jackson.databind.JsonNode;
38+
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
39+
import com.fasterxml.jackson.databind.node.ObjectNode;
40+
3241
/**
3342
* User entity for tests
3443
*
@@ -40,14 +49,34 @@
4049
@TypeAlias(AbstractingTypeMapper.Type.ABSTRACTUSER)
4150
public class User extends AbstractUser implements Serializable {
4251

52+
public JsonNode jsonNode;
53+
public JsonObject jsonObject;
54+
public JsonArray jsonArray;
55+
4356
@PersistenceConstructor
4457
public User(final String id, final String firstname, final String lastname) {
4558
this.id = id;
4659
this.firstname = firstname;
4760
this.lastname = lastname;
4861
this.subtype = AbstractingTypeMapper.Type.USER;
62+
this.jsonNode = new ObjectNode(JsonNodeFactory.instance);
63+
try {
64+
jsonNode = (new ObjectNode(JsonNodeFactory.instance)).put("myNumber", uid());
65+
} catch (Exception e) {
66+
e.printStackTrace();
67+
}
68+
Map map = new HashMap();
69+
map.put("myNumber", uid());
70+
this.jsonObject = JsonObject.jo().put("yourNumber",Long.valueOf(uid()));
71+
this.jsonArray = JsonArray.from(Long.valueOf(uid()), Long.valueOf(uid()));
4972
}
5073

74+
@Transient int uid=1000;
75+
long uid(){
76+
return uid++;
77+
}
78+
79+
5180
@Version protected long version;
5281
@Transient protected String transientInfo;
5382
@CreatedBy protected String createdBy;

Diff for: src/test/java/org/springframework/data/couchbase/repository/query/StringN1qlQueryCreatorTests.java

+5-7
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ void createsQueryCorrectly() throws Exception {
110110

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

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

152152
Query query = creator.createQuery();
153153

154-
assertEquals(
155-
"SELECT `_class`, META(`myCollection`).`cas` AS __cas, `createdBy`, `createdDate`, "
156-
+ "`lastModifiedBy`, `lastModifiedDate`, META(`myCollection`).`id` AS __id, `firstname`, "
157-
+ "`lastname`, `subtype` FROM `myCollection`|`_class` = \"abstractuser\""
158-
+ "|`myCollection`|`myScope`|`myCollection`",
154+
assertEquals("SELECT `_class`, `jsonNode`, `jsonObject`, `jsonArray`, META(`myCollection`).`cas`"
155+
+ " AS __cas, `createdBy`, `createdDate`, `lastModifiedBy`, `lastModifiedDate`, META(`myCollection`).`id`"
156+
+ " AS __id, `firstname`, `lastname`, `subtype` FROM `myCollection`|`_class` = \"abstractuser\"|`myCollection`|`myScope`|`myCollection`",
159157
query.toN1qlSelectString(converter, bucketName(), "myScope", "myCollection", User.class, null, false, null,
160158
null));
161159
}

0 commit comments

Comments
 (0)