Skip to content

Commit 9771679

Browse files
SDKQE-3406 :- Add custom serializer in seach option
1. Add pass serializer search option is custom serializer is set to true 2. Implement a custom serializer 3. check if fields in result are null, then don't parse then according to the fieldAs input Change-Id: I498d9d3316a3587e2e925206a931f283fe814c43 Reviewed-on: https://review.couchbase.org/c/couchbase-jvm-clients/+/214786 Reviewed-by: Graham Pople <graham.pople@couchbase.com> Tested-by: Build Bot <build@couchbase.com>
1 parent b825e4a commit 9771679

File tree

3 files changed

+114
-15
lines changed

3 files changed

+114
-15
lines changed

java-fit-performer/src/main/java/com/couchbase/search/SearchHelper.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
import com.couchbase.client.protocol.shared.ContentAs;
8989
import com.couchbase.stream.ReactiveSearchResultStreamer;
9090
import com.couchbase.utils.ContentAsUtil;
91+
import com.couchbase.utils.CustomJsonSerializer;
9192
import com.google.common.primitives.Floats;
9293
import com.google.protobuf.ByteString;
9394
import com.google.protobuf.Timestamp;
@@ -292,6 +293,13 @@ static SearchOptions convertSearchOptions(boolean hasOptions, com.couchbase.clie
292293
opts.includeLocations(o.getIncludeLocations());
293294
}
294295

296+
if (o.hasSerialize()) {
297+
if (o.getSerialize().hasCustomSerializer() && o.getSerialize().getCustomSerializer()) {
298+
CustomJsonSerializer customSerializer = new CustomJsonSerializer();
299+
opts.serializer(customSerializer);
300+
}
301+
}
302+
295303
return opts;
296304
}
297305

java-fit-performer/src/main/java/com/couchbase/utils/ContentAsUtil.java

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@
2525
import java.util.function.Supplier;
2626

2727
public class ContentAsUtil {
28+
private static Try<ContentTypes> getNullContentType(){
29+
return new Try<>(ContentTypes.newBuilder().
30+
setContentAsNull(ContentTypes.NullValue.newBuilder()
31+
.getDefaultInstanceForType()).build()
32+
);
33+
}
34+
2835
public static Try<ContentTypes> contentType(ContentAs contentAs,
2936
Supplier<byte[]> asByteArray,
3037
Supplier<String> asString,
@@ -35,32 +42,46 @@ public static Try<ContentTypes> contentType(ContentAs contentAs,
3542
Supplier<Double> asDouble) {
3643
try {
3744
if (contentAs.hasAsByteArray()) {
45+
byte[] byteArray = asByteArray.get();
46+
if (byteArray == null) return getNullContentType();
3847
return new Try<>(ContentTypes.newBuilder()
39-
.setContentAsBytes(ByteString.copyFrom(asByteArray.get()))
48+
.setContentAsBytes(ByteString.copyFrom(byteArray))
4049
.build());
4150
} else if (contentAs.hasAsString()) {
51+
String string = asString.get();
52+
if (string == null) return getNullContentType();
4253
return new Try<>(ContentTypes.newBuilder()
43-
.setContentAsString(asString.get())
54+
.setContentAsString(string)
4455
.build());
4556
} else if (contentAs.hasAsJsonObject()) {
57+
JsonObject jsonObject = asJsonObject.get();
58+
if (jsonObject == null) return getNullContentType();
4659
return new Try<>(ContentTypes.newBuilder()
47-
.setContentAsBytes(ByteString.copyFrom(asJsonObject.get().toBytes()))
60+
.setContentAsBytes(ByteString.copyFrom(jsonObject.toBytes()))
4861
.build());
4962
} else if (contentAs.hasAsJsonArray()) {
63+
JsonArray jsonArray = asJsonArray.get();
64+
if (jsonArray == null) return getNullContentType();
5065
return new Try<>(ContentTypes.newBuilder()
51-
.setContentAsBytes(ByteString.copyFrom(asJsonArray.get().toBytes()))
66+
.setContentAsBytes(ByteString.copyFrom(jsonArray.toBytes()))
5267
.build());
5368
} else if (contentAs.getAsBoolean()) {
69+
Boolean bool = asBoolean.get();
70+
if (bool == null) return getNullContentType();
5471
return new Try<>(ContentTypes.newBuilder()
55-
.setContentAsBool(asBoolean.get())
72+
.setContentAsBool(bool)
5673
.build());
5774
} else if (contentAs.hasAsInteger()) {
75+
Integer integer = asInteger.get();
76+
if (integer == null) return getNullContentType();
5877
return new Try<>(ContentTypes.newBuilder()
59-
.setContentAsInt64(asInteger.get())
78+
.setContentAsInt64(integer)
6079
.build());
6180
} else if (contentAs.hasAsFloatingPoint()) {
81+
Double dbl = asDouble.get();
82+
if (dbl == null) return getNullContentType();
6283
return new Try<>(ContentTypes.newBuilder()
63-
.setContentAsDouble(asDouble.get())
84+
.setContentAsDouble(dbl)
6485
.build());
6586
} else {
6687
throw new UnsupportedOperationException("Java performer cannot handle contentAs " + contentAs.toString());
@@ -81,31 +102,44 @@ public static Try<List<ContentTypes>> contentTypeList(ContentAs contentAs,
81102
try {
82103
if (contentAs.hasAsByteArray()) {
83104
return new Try<>(asByteArray.get().stream()
84-
.map(v -> ContentTypes.newBuilder().setContentAsBytes(ByteString.copyFrom(v)).build())
105+
.map(v -> v != null
106+
? ContentTypes.newBuilder().setContentAsBytes(ByteString.copyFrom(v)).build()
107+
: getNullContentType().value())
85108
.toList());
86109
} else if (contentAs.hasAsString()) {
87110
return new Try<>(asString.get().stream()
88-
.map(v -> ContentTypes.newBuilder().setContentAsString(v).build())
89-
.toList());
111+
.map(v -> v != null
112+
? ContentTypes.newBuilder().setContentAsString(v).build()
113+
: getNullContentType().value()).toList());
90114
} else if (contentAs.hasAsJsonObject()) {
91115
return new Try<>(asJsonObject.get().stream()
92-
.map(v -> ContentTypes.newBuilder().setContentAsBytes(ByteString.copyFrom(v.toBytes())).build())
116+
.map(v -> v != null
117+
? ContentTypes.newBuilder().setContentAsBytes(ByteString.copyFrom(v.toBytes())).build()
118+
: getNullContentType().value())
93119
.toList());
94120
} else if (contentAs.hasAsJsonArray()) {
95121
return new Try<>(asJsonArray.get().stream()
96-
.map(v -> ContentTypes.newBuilder().setContentAsBytes(ByteString.copyFrom(v.toBytes())).build())
122+
.map(v -> v != null
123+
? ContentTypes.newBuilder().setContentAsBytes(ByteString.copyFrom(v.toBytes())).build()
124+
: getNullContentType().value())
97125
.toList());
98126
} else if (contentAs.getAsBoolean()) {
99127
return new Try<>(asBoolean.get().stream()
100-
.map(v -> ContentTypes.newBuilder().setContentAsBool(v).build())
128+
.map(v -> v != null
129+
? ContentTypes.newBuilder().setContentAsBool(v).build()
130+
: getNullContentType().value())
101131
.toList());
102132
} else if (contentAs.hasAsInteger()) {
103133
return new Try<>(asInteger.get().stream()
104-
.map(v -> ContentTypes.newBuilder().setContentAsInt64(v).build())
134+
.map(v -> v != null
135+
? ContentTypes.newBuilder().setContentAsInt64(v).build()
136+
: getNullContentType().value())
105137
.toList());
106138
} else if (contentAs.hasAsFloatingPoint()) {
107139
return new Try<>(asDouble.get().stream()
108-
.map(v -> ContentTypes.newBuilder().setContentAsDouble(v).build())
140+
.map(v -> v != null
141+
?ContentTypes.newBuilder().setContentAsDouble(v).build()
142+
: getNullContentType().value())
109143
.toList());
110144
} else {
111145
throw new UnsupportedOperationException("Java performer cannot handle contentAs " + contentAs.toString());
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* CustomJsonSerializer provides a generic implementation of the JsonSerializer interface.
3+
4+
* This serializer is designed to handle the conversion of Java objects to JSON format
5+
* and back, with an additional boolean flag (`Serialized`) that indicates whether
6+
* the object has been serialized. The flag is included in the JSON payload, making
7+
* it easy to track the serialization state of objects.
8+
9+
* Use Cases:
10+
* - This serializer can be used in scenarios where you need to serialize and deserialize
11+
* objects while keeping track of their serialization state.
12+
13+
* Limitations:
14+
* - The current implementation assumes that the input objects can be serialized into
15+
* a JSON format using Jackson's ObjectMapper. Complex or non-standard objects may
16+
* require additional handling.
17+
* - The `deserialize` methods in this implementation modify the original JSON object
18+
* by setting the `Serialized` flag to `false`, which might not be suitable for
19+
* all use cases.
20+
*/
21+
22+
package com.couchbase.utils;
23+
24+
import com.couchbase.client.core.deps.com.fasterxml.jackson.core.JsonProcessingException;
25+
import com.couchbase.client.core.error.DecodingFailureException;
26+
import com.couchbase.client.core.json.Mapper;
27+
import com.couchbase.client.java.codec.JsonSerializer;
28+
import com.couchbase.client.java.codec.TypeRef;
29+
import com.couchbase.client.java.json.JsonObject;
30+
31+
32+
public class CustomJsonSerializer implements JsonSerializer {
33+
@Override
34+
public byte[] serialize(Object input) {
35+
try {
36+
String json = Mapper.writer().writeValueAsString(input);
37+
var obj = JsonObject.create().put("Serialized", true);
38+
return obj.toBytes();
39+
} catch (JsonProcessingException e) {
40+
throw new DecodingFailureException(e);
41+
}
42+
}
43+
44+
@Override
45+
public <T> T deserialize(Class<T> target, byte[] input) {
46+
JsonObject obj = JsonObject.fromJson(input);
47+
obj.put("Serialized", false);
48+
return (T) obj;
49+
}
50+
51+
@Override
52+
public <T> T deserialize(TypeRef<T> target, byte[] input) {
53+
JsonObject obj = JsonObject.fromJson(input);
54+
obj.put("Serialized", false);
55+
return (T) obj;
56+
}
57+
}

0 commit comments

Comments
 (0)