Skip to content

Commit d7f98ef

Browse files
Use Jackson as the default JSON implementations, update libraries (#976) (#980)
Co-authored-by: Sylvain Wallez <[email protected]>
1 parent 750215e commit d7f98ef

File tree

10 files changed

+85
-65
lines changed

10 files changed

+85
-65
lines changed

docs/reference/getting-started.md

-7
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ This page guides you through the installation process of the Java client, shows
2222
```groovy
2323
dependencies {
2424
implementation 'co.elastic.clients:elasticsearch-java:9.0.0-beta1'
25-
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0'
2625
}
2726
```
2827

@@ -41,12 +40,6 @@ In the `pom.xml` of your project, add the following repository definition and de
4140
<version>9.0.0-beta1</version>
4241
</dependency>
4342

44-
<dependency>
45-
<groupId>com.fasterxml.jackson.core</groupId>
46-
<artifactId>jackson-databind</artifactId>
47-
<version>2.17.0</version>
48-
</dependency>
49-
5043
</dependencies>
5144
</project>
5245
```

docs/reference/installation.md

-7
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ Releases are hosted on [Maven Central](https://search.maven.org/search?q=g:co.el
1818
```groovy
1919
dependencies {
2020
implementation 'co.elastic.clients:elasticsearch-java:9.0.0-beta1'
21-
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0'
2221
}
2322
```
2423

@@ -37,12 +36,6 @@ In the `pom.xml` of your project, add the following repository definition and de
3736
<version>9.0.0-beta1</version>
3837
</dependency>
3938

40-
<dependency>
41-
<groupId>com.fasterxml.jackson.core</groupId>
42-
<artifactId>jackson-databind</artifactId>
43-
<version>2.17.0</version>
44-
</dependency>
45-
4639
</dependencies>
4740
</project>
4841
```

java-client/build.gradle.kts

+25-29
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ publishing {
160160
}
161161

162162
withXml {
163+
// Note: org.elasticsearch.client is now an optional dependency, so the below is no more useful.
164+
// It's kept in case it ever comes back as a required dependency.
165+
163166
// Set the version of dependencies of the org.elasticsearch.client group to the one that we are building.
164167
// Since the unified release process releases everything at once, this ensures all published artifacts depend
165168
// on the exact same version. This assumes of course that the binary API and the behavior of these dependencies
@@ -169,21 +172,14 @@ publishing {
169172
.compile("/project/dependencies/dependency[groupId/text() = 'org.elasticsearch.client']")
170173
val versionSelector = xPathFactory.newXPath().compile("version")
171174

172-
var foundVersion = false;
173-
174175
val deps = depSelector.evaluate(asElement().ownerDocument, javax.xml.xpath.XPathConstants.NODESET)
175176
as org.w3c.dom.NodeList
176177

177178
for (i in 0 until deps.length) {
178179
val dep = deps.item(i)
179180
val version = versionSelector.evaluate(dep, javax.xml.xpath.XPathConstants.NODE) as org.w3c.dom.Element
180-
foundVersion = true;
181181
version.textContent = project.version.toString()
182182
}
183-
184-
if (!foundVersion) {
185-
throw GradleException("Could not find a 'org.elasticsearch.client' to update dependency version in the POM.")
186-
}
187183
}
188184
}
189185
}
@@ -198,15 +194,16 @@ signing {
198194
}
199195

200196
dependencies {
201-
// Compile and test with the last 7.x version to make sure transition scenarios where
202-
// the Java API client coexists with a 7.x HLRC work fine
197+
// Compile and test with the last 8.x version to make sure transition scenarios where
198+
// the Java API client coexists with a 8.x HLRC work fine
203199
val elasticsearchVersion = "8.17.0"
204-
val jacksonVersion = "2.17.0"
200+
val jacksonVersion = "2.18.3"
205201
val openTelemetryVersion = "1.29.0"
206202

207203
// Apache 2.0
208204
// https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-low.html
209-
api("org.elasticsearch.client", "elasticsearch-rest-client", elasticsearchVersion)
205+
compileOnly("org.elasticsearch.client", "elasticsearch-rest-client", elasticsearchVersion)
206+
testImplementation("org.elasticsearch.client", "elasticsearch-rest-client", elasticsearchVersion)
210207

211208
api("org.apache.httpcomponents.client5","httpclient5","5.4")
212209

@@ -216,38 +213,34 @@ dependencies {
216213

217214
// EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
218215
// https://github.com/eclipse-ee4j/jsonp
219-
api("jakarta.json:jakarta.json-api:2.0.1")
216+
api("jakarta.json:jakarta.json-api:2.1.3")
220217

221218
// Needed even if using Jackson to have an implementation of the Jsonp object model
222219
// EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
223220
// https://github.com/eclipse-ee4j/parsson
224-
api("org.eclipse.parsson:parsson:1.0.5")
221+
api("org.eclipse.parsson:parsson:1.1.7")
225222

226223
// OpenTelemetry API for native instrumentation of the client.
227224
// Apache 2.0
228225
// https://github.com/open-telemetry/opentelemetry-java
229226
implementation("io.opentelemetry", "opentelemetry-api", openTelemetryVersion)
230227
// Use it once it's stable (see Instrumentation.java). Limited to tests for now.
231228
testImplementation("io.opentelemetry", "opentelemetry-semconv", "$openTelemetryVersion-alpha")
229+
testImplementation("io.opentelemetry", "opentelemetry-sdk", openTelemetryVersion)
232230

233231
// EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
234232
// https://github.com/eclipse-ee4j/jsonb-api
235-
compileOnly("jakarta.json.bind", "jakarta.json.bind-api", "2.0.0")
236-
testImplementation("jakarta.json.bind", "jakarta.json.bind-api", "2.0.0")
233+
compileOnly("jakarta.json.bind", "jakarta.json.bind-api", "3.0.1")
234+
testImplementation("jakarta.json.bind", "jakarta.json.bind-api", "3.0.1")
237235

238236
// Apache 2.0
239237
// https://github.com/FasterXML/jackson
240-
compileOnly("com.fasterxml.jackson.core", "jackson-core", jacksonVersion)
241-
compileOnly("com.fasterxml.jackson.core", "jackson-databind", jacksonVersion)
242-
testImplementation("com.fasterxml.jackson.core", "jackson-core", jacksonVersion)
243-
testImplementation("com.fasterxml.jackson.core", "jackson-databind", jacksonVersion)
238+
implementation("com.fasterxml.jackson.core", "jackson-core", jacksonVersion)
239+
implementation("com.fasterxml.jackson.core", "jackson-databind", jacksonVersion)
244240

245241
// EPL-2.0 OR BSD-3-Clause
246242
// https://eclipse-ee4j.github.io/yasson/
247-
testImplementation("org.eclipse", "yasson", "2.0.4") {
248-
// Exclude Glassfish as we use Parsson (basically Glassfish renamed in the Jakarta namespace).
249-
exclude(group = "org.glassfish", module = "jakarta.json")
250-
}
243+
testImplementation("org.eclipse", "yasson", "3.0.4")
251244

252245
// Apache-2.0
253246
testImplementation("commons-io:commons-io:2.17.0")
@@ -268,8 +261,6 @@ dependencies {
268261
// updating transitive dependency from testcontainers
269262
testImplementation("org.apache.commons","commons-compress","1.26.1")
270263

271-
testImplementation("io.opentelemetry", "opentelemetry-sdk", openTelemetryVersion)
272-
273264
// Apache-2.0
274265
// https://github.com/awaitility/awaitility
275266
testImplementation("org.awaitility", "awaitility", "4.2.0")
@@ -324,10 +315,15 @@ class SpdxReporter(val dest: File) : ReportRenderer {
324315
val depName = dep.group + ":" + dep.name
325316

326317
val info = LicenseDataCollector.multiModuleLicenseInfo(dep)
327-
val depUrl = if (depName.startsWith("org.apache.httpcomponents")) {
328-
"https://hc.apache.org/"
329-
} else {
330-
info.moduleUrls.first()
318+
val depUrl = when(dep.group) {
319+
"org.apache.httpcomponents.client5" -> "https://hc.apache.org/"
320+
"org.apache.httpcomponents.core5" -> "https://hc.apache.org/"
321+
"com.fasterxml.jackson" -> "https://github.com/FasterXML/jackson"
322+
else -> if (info.moduleUrls.isEmpty()) {
323+
throw RuntimeException("No URL found for module '$depName'")
324+
} else {
325+
info.moduleUrls.first()
326+
}
331327
}
332328

333329
val licenseIds = info.licenses.mapNotNull { license ->

java-client/src/main/java/co/elastic/clients/json/JsonpUtils.java

+36-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package co.elastic.clients.json;
2121

22+
import co.elastic.clients.json.jackson.JacksonJsonProvider;
2223
import co.elastic.clients.util.AllowForbiddenApis;
2324
import jakarta.json.JsonException;
2425
import jakarta.json.JsonObject;
@@ -43,23 +44,56 @@
4344
public class JsonpUtils {
4445

4546
private static JsonProvider systemJsonProvider = null;
47+
private static JsonProvider defaultJsonProvider = null;
4648

4749
/**
4850
* Get a <code>JsonProvider</code> instance. This method first calls the standard `JsonProvider.provider()` that is based on
4951
* the current thread's context classloader, and in case of failure tries to find a provider in other classloaders. The
5052
* value is cached for subsequent calls.
5153
*/
5254
public static JsonProvider provider() {
53-
JsonProvider result = systemJsonProvider;
55+
JsonProvider result = defaultJsonProvider;
5456
if (result == null) {
5557
result = findProvider();
58+
defaultJsonProvider = result;
59+
}
60+
return result;
61+
}
62+
63+
/**
64+
* Sets the <code>JsonProvider</code> that will be returned by {@link JsonProvider}.
65+
*/
66+
public static void setProvider(JsonProvider provider) {
67+
defaultJsonProvider = provider;
68+
}
69+
70+
static JsonProvider findProvider() {
71+
try {
72+
// Default to Jackson
73+
Class.forName("com.fasterxml.jackson.databind.ObjectMapper");
74+
return new JacksonJsonProvider();
75+
} catch (ClassNotFoundException e) {
76+
return findSystemProvider();
77+
}
78+
}
79+
80+
/**
81+
* Get the system's <code>JsonProvider</code> instance return by {@code ServiceLoader}. First calls the standard
82+
* `JsonProvider.provider()` that is based on the current thread's context classloader, and in case of failure tries to
83+
* find a provider in other classloaders. The value is cached for subsequent calls.
84+
*/
85+
public static JsonProvider systemProvider() {
86+
JsonProvider result = systemJsonProvider;
87+
if (result == null) {
88+
result = findSystemProvider();
5689
systemJsonProvider = result;
5790
}
5891
return result;
5992
}
6093

6194
@AllowForbiddenApis("Implementation of the JsonProvider lookup")
62-
static JsonProvider findProvider() {
95+
static JsonProvider findSystemProvider() {
96+
6397
RuntimeException exception;
6498
try {
6599
return JsonProvider.provider();

java-client/src/main/java/co/elastic/clients/json/SimpleJsonpMapper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public boolean ignoreUnknownFields() {
9090

9191
@Override
9292
public JsonProvider jsonProvider() {
93-
return JsonpUtils.provider();
93+
return JsonpUtils.systemProvider();
9494
}
9595

9696
@Override

java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonProvider.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,15 @@ public JsonParser createParser(InputStream in, Charset charset) {
133133
*/
134134
@Override
135135
public JsonParser createParser(JsonObject obj) {
136-
return JsonpUtils.provider().createParserFactory(null).createParser(obj);
136+
return JsonpUtils.systemProvider().createParserFactory(null).createParser(obj);
137137
}
138138

139139
/**
140140
* Not implemented.
141141
*/
142142
@Override
143143
public JsonParser createParser(JsonArray array) {
144-
return JsonpUtils.provider().createParserFactory(null).createParser(array);
144+
return JsonpUtils.systemProvider().createParserFactory(null).createParser(array);
145145
}
146146

147147
/**

java-client/src/main/java/co/elastic/clients/json/jackson/JsonValueParser.java

+8-8
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@
4040
* object (e.g. START_OBJECT, VALUE_NUMBER, etc).
4141
*/
4242
class JsonValueParser {
43-
private final JsonProvider provider = JsonpUtils.provider();
43+
private final JsonProvider systemProvider = JsonpUtils.systemProvider();
4444

4545
public JsonObject parseObject(JsonParser parser) throws IOException {
4646

47-
JsonObjectBuilder ob = provider.createObjectBuilder();
47+
JsonObjectBuilder ob = systemProvider.createObjectBuilder();
4848

4949
JsonToken token;
5050
while((token = parser.nextToken()) != JsonToken.END_OBJECT) {
@@ -59,7 +59,7 @@ public JsonObject parseObject(JsonParser parser) throws IOException {
5959
}
6060

6161
public JsonArray parseArray(JsonParser parser) throws IOException {
62-
JsonArrayBuilder ab = provider.createArrayBuilder();
62+
JsonArrayBuilder ab = systemProvider.createArrayBuilder();
6363

6464
while(parser.nextToken() != JsonToken.END_ARRAY) {
6565
ab.add(parseValue(parser));
@@ -86,23 +86,23 @@ public JsonValue parseValue(JsonParser parser) throws IOException {
8686
return JsonValue.NULL;
8787

8888
case VALUE_STRING:
89-
return provider.createValue(parser.getText());
89+
return systemProvider.createValue(parser.getText());
9090

9191
case VALUE_NUMBER_FLOAT:
9292
case VALUE_NUMBER_INT:
9393
switch(parser.getNumberType()) {
9494
case INT:
95-
return provider.createValue(parser.getIntValue());
95+
return systemProvider.createValue(parser.getIntValue());
9696
case LONG:
97-
return provider.createValue(parser.getLongValue());
97+
return systemProvider.createValue(parser.getLongValue());
9898
case FLOAT:
9999
case DOUBLE:
100100
// Use double also for floats, as JSON-P has no support for float
101101
return new DoubleNumber(parser.getDoubleValue());
102102
case BIG_DECIMAL:
103-
return provider.createValue(parser.getDecimalValue());
103+
return systemProvider.createValue(parser.getDecimalValue());
104104
case BIG_INTEGER:
105-
return provider.createValue(parser.getBigIntegerValue());
105+
return systemProvider.createValue(parser.getBigIntegerValue());
106106
}
107107

108108
default:

java-client/src/main/java/co/elastic/clients/json/jsonb/JsonbJsonpMapper.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public JsonbJsonpMapper(JsonProvider jsonProvider, JsonbProvider jsonbProvider)
5252
}
5353

5454
public JsonbJsonpMapper() {
55-
this(JsonpUtils.provider(), JsonbProvider.provider());
55+
// Use a native JSON-P/JSON-B implementations.
56+
this(JsonpUtils.systemProvider(), JsonbProvider.provider());
5657
}
5758

5859
@Override

java-client/src/test/java/co/elastic/clients/json/JsonpUtilsTest.java

+10-7
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
package co.elastic.clients.json;
2121

2222
import co.elastic.clients.elasticsearch.core.search.Hit;
23+
import co.elastic.clients.json.jackson.JacksonJsonProvider;
2324
import co.elastic.clients.testkit.ModelTestCase;
2425
import co.elastic.clients.elasticsearch.security.IndexPrivilege;
2526
import co.elastic.clients.elasticsearch.security.IndicesPrivileges;
2627
import co.elastic.clients.elasticsearch.security.RoleTemplateScript;
2728
import co.elastic.clients.elasticsearch.security.UserIndicesPrivileges;
2829
import co.elastic.clients.util.AllowForbiddenApis;
29-
import jakarta.json.JsonException;
3030
import jakarta.json.spi.JsonProvider;
3131
import jakarta.json.stream.JsonGenerator;
3232
import jakarta.json.stream.JsonParser;
@@ -58,13 +58,7 @@ public Enumeration<URL> getResources(String name) {
5858
ClassLoader savedLoader = Thread.currentThread().getContextClassLoader();
5959
try {
6060
Thread.currentThread().setContextClassLoader(emptyLoader);
61-
62-
assertThrows(JsonException.class, () -> {
63-
assertNotNull(JsonProvider.provider());
64-
});
65-
6661
assertNotNull(JsonpUtils.provider());
67-
6862
} finally {
6963
Thread.currentThread().setContextClassLoader(savedLoader);
7064
}
@@ -91,6 +85,15 @@ public void testObjectToString() {
9185
assertEquals("Hit: {\"_index\":\"idx\",\"_id\":\"id1\",\"_source\":\"Some user data\"}", hit.toString());
9286
}
9387

88+
@Test
89+
public void testDefaultProvider() {
90+
// Provider defaults to Jackson
91+
assertTrue(JsonpUtils.provider() instanceof JacksonJsonProvider);
92+
93+
// System provider uses service lookup
94+
assertFalse(JsonpUtils.systemProvider() instanceof JacksonJsonProvider);
95+
}
96+
9497
private static class SomeUserData {
9598
@Override
9699
public String toString() {

java-client/src/test/java/co/elastic/clients/testkit/ModelTestCase.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ protected enum JsonImpl { Jsonb, Jackson, Simple };
5050
protected final JsonpMapper mapper;
5151

5252
private static JsonImpl chooseJsonImpl(EnumSet<JsonImpl> jsonImplCandidates, int rand) {
53-
// Converting an EnumSet to an array always uses the same order.
53+
// Converting an EnumSet an array always uses the same order.
5454
return jsonImplCandidates.toArray(new JsonImpl[jsonImplCandidates.size()])[rand % jsonImplCandidates.size()];
5555
}
5656

0 commit comments

Comments
 (0)