-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[DE-762] configure jackson stream constraints (#537)
* configure Jackson StreamReadConstraints and StreamWriteConstraints with permissive values * test JSON serde with big strings * fix native tests * fix shaded native tests
- Loading branch information
Showing
11 changed files
with
500 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
102 changes: 102 additions & 0 deletions
102
core/src/main/java/com/arangodb/internal/serde/JacksonUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package com.arangodb.internal.serde; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public final class JacksonUtils { | ||
private static final Logger LOG = LoggerFactory.getLogger(JacksonUtils.class); | ||
|
||
private JacksonUtils() { | ||
} | ||
|
||
/** | ||
* Configure JsonFactory with permissive StreamReadConstraints and StreamWriteConstraints. | ||
* It uses reflection to avoid compilation errors with older Jackson versions. | ||
* It uses dynamic package names to be compatible with shaded Jackson. | ||
* | ||
* @param jf JsonFactory to configure | ||
*/ | ||
public static void tryConfigureJsonFactory(Object jf) { | ||
try { | ||
configureJsonFactory(jf); | ||
} catch (Throwable t) { | ||
LOG.warn("Got exception while configuring JsonFactory, skipping...", t); | ||
} | ||
} | ||
|
||
private static void configureJsonFactory(Object jf) throws Exception { | ||
// using reflection because these configuration are not supported in older Jackson versions | ||
if (isAtLeastVersion(jf, 2, 15)) { | ||
LOG.debug("Configuring StreamReadConstraints ..."); | ||
List<Invocation> readConf = new ArrayList<>(); | ||
readConf.add(new Invocation("maxNumberLength", int.class, Integer.MAX_VALUE)); | ||
readConf.add(new Invocation("maxStringLength", int.class, Integer.MAX_VALUE)); | ||
readConf.add(new Invocation("maxNestingDepth", int.class, Integer.MAX_VALUE)); | ||
if (isAtLeastVersion(jf, 2, 16)) { | ||
readConf.add(new Invocation("maxNameLength", int.class, Integer.MAX_VALUE)); | ||
readConf.add(new Invocation("maxDocumentLength", long.class, Long.MAX_VALUE)); | ||
} else { | ||
LOG.debug("Skipping configuring StreamReadConstraints maxNameLength"); | ||
LOG.debug("Skipping configuring StreamReadConstraints maxDocumentLength"); | ||
} | ||
configureStreamConstraints(jf, "StreamReadConstraints", readConf); | ||
} else { | ||
LOG.debug("Skipping configuring StreamReadConstraints"); | ||
} | ||
|
||
if (isAtLeastVersion(jf, 2, 16)) { | ||
LOG.debug("Configuring StreamWriteConstraints ..."); | ||
List<Invocation> writeConf = new ArrayList<>(); | ||
writeConf.add(new Invocation("maxNestingDepth", int.class, Integer.MAX_VALUE)); | ||
configureStreamConstraints(jf, "StreamWriteConstraints", writeConf); | ||
} else { | ||
LOG.debug("Skipping configuring StreamWriteConstraints"); | ||
} | ||
} | ||
|
||
private static boolean isAtLeastVersion(Object jf, int major, int minor) throws Exception { | ||
Class<?> packageVersionClass = Class.forName(jf.getClass().getPackage().getName() + ".json.PackageVersion"); | ||
Object version = packageVersionClass.getDeclaredField("VERSION").get(null); | ||
|
||
Class<?> versionClass = Class.forName(jf.getClass().getPackage().getName() + ".Version"); | ||
int currentMajor = (int) versionClass.getDeclaredMethod("getMajorVersion").invoke(version); | ||
int currentMinor = (int) versionClass.getDeclaredMethod("getMinorVersion").invoke(version); | ||
|
||
LOG.debug("Detected Jackson version: {}.{}", currentMajor, currentMinor); | ||
|
||
return currentMajor > major || (currentMajor == major && currentMinor >= minor); | ||
} | ||
|
||
private static void configureStreamConstraints(Object jf, String className, List<Invocation> conf) throws Exception { | ||
// get pkg name dynamically, to support shaded Jackson | ||
String basePkg = jf.getClass().getPackage().getName(); | ||
Class<?> streamConstraintsClass = Class.forName(basePkg + "." + className); | ||
Class<?> builderClass = Class.forName(basePkg + "." + className + "$Builder"); | ||
Method buildMethod = builderClass.getDeclaredMethod("build"); | ||
Method builderMethod = streamConstraintsClass.getDeclaredMethod("builder"); | ||
Object builder = builderMethod.invoke(null); | ||
for (Invocation i : conf) { | ||
Method method = builderClass.getDeclaredMethod(i.method, i.argType); | ||
method.invoke(builder, i.arg); | ||
} | ||
Object streamReadConstraints = buildMethod.invoke(builder); | ||
Method setStreamReadConstraintsMethod = jf.getClass().getDeclaredMethod("set" + className, streamConstraintsClass); | ||
setStreamReadConstraintsMethod.invoke(jf, streamReadConstraints); | ||
} | ||
|
||
private static class Invocation { | ||
final String method; | ||
final Class<?> argType; | ||
final Object arg; | ||
|
||
Invocation(String method, Class<?> argType, Object arg) { | ||
this.method = method; | ||
this.argType = argType; | ||
this.arg = arg; | ||
} | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
...resources/META-INF/native-image/com.arangodb/arangodb-java-driver/native-image.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
...sources/META-INF/native-image/com.arangodb/arangodb-java-driver/reflect-config-serde.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
[ | ||
{ | ||
"name": "com.fasterxml.jackson.core.JsonFactory", | ||
"methods": [ | ||
{ | ||
"name": "setStreamReadConstraints", | ||
"parameterTypes": [ | ||
"com.fasterxml.jackson.core.StreamReadConstraints" | ||
] | ||
}, | ||
{ | ||
"name": "setStreamWriteConstraints", | ||
"parameterTypes": [ | ||
"com.fasterxml.jackson.core.StreamWriteConstraints" | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
"name": "com.fasterxml.jackson.core.StreamReadConstraints", | ||
"methods": [ | ||
{ | ||
"name": "builder", | ||
"parameterTypes": [] | ||
} | ||
] | ||
}, | ||
{ | ||
"name": "com.fasterxml.jackson.core.StreamReadConstraints$Builder", | ||
"methods": [ | ||
{ | ||
"name": "build", | ||
"parameterTypes": [] | ||
}, | ||
{ | ||
"name": "maxDocumentLength", | ||
"parameterTypes": [ | ||
"long" | ||
] | ||
}, | ||
{ | ||
"name": "maxNameLength", | ||
"parameterTypes": [ | ||
"int" | ||
] | ||
}, | ||
{ | ||
"name": "maxNestingDepth", | ||
"parameterTypes": [ | ||
"int" | ||
] | ||
}, | ||
{ | ||
"name": "maxNumberLength", | ||
"parameterTypes": [ | ||
"int" | ||
] | ||
}, | ||
{ | ||
"name": "maxStringLength", | ||
"parameterTypes": [ | ||
"int" | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
"name": "com.fasterxml.jackson.core.StreamWriteConstraints", | ||
"methods": [ | ||
{ | ||
"name": "builder", | ||
"parameterTypes": [] | ||
} | ||
] | ||
}, | ||
{ | ||
"name": "com.fasterxml.jackson.core.StreamWriteConstraints$Builder", | ||
"methods": [ | ||
{ | ||
"name": "build", | ||
"parameterTypes": [] | ||
}, | ||
{ | ||
"name": "maxNestingDepth", | ||
"parameterTypes": [ | ||
"int" | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
"name": "com.fasterxml.jackson.core.Version", | ||
"methods": [ | ||
{ | ||
"name": "getMajorVersion", | ||
"parameterTypes": [] | ||
}, | ||
{ | ||
"name": "getMinorVersion", | ||
"parameterTypes": [] | ||
} | ||
] | ||
}, | ||
{ | ||
"name": "com.fasterxml.jackson.core.json.PackageVersion", | ||
"fields": [ | ||
{ | ||
"name": "VERSION" | ||
} | ||
] | ||
} | ||
] |
47 changes: 47 additions & 0 deletions
47
driver/src/test/java/com/arangodb/serde/JacksonConfigurationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package com.arangodb.serde; | ||
|
||
import com.arangodb.ContentType; | ||
import com.arangodb.internal.serde.InternalSerdeProvider; | ||
import com.arangodb.serde.jackson.JacksonSerde; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.EnumSource; | ||
|
||
import java.util.UUID; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
public class JacksonConfigurationTest { | ||
|
||
@ParameterizedTest | ||
@EnumSource(ContentType.class) | ||
void bigStringInternalSerde(ContentType type) { | ||
ArangoSerde s = new InternalSerdeProvider(type).create(); | ||
|
||
StringBuilder sb = new StringBuilder(); | ||
while (sb.length() < 40_000_000) { | ||
sb.append(UUID.randomUUID()); | ||
} | ||
String in = sb.toString(); | ||
byte[] bytes = s.serialize(in); | ||
String out = s.deserialize(bytes, String.class); | ||
assertThat(out).isEqualTo(in); | ||
} | ||
|
||
@ParameterizedTest | ||
@EnumSource(ContentType.class) | ||
void bigStringUserSerde(ContentType type) { | ||
ArangoSerde s = JacksonSerde.of(type); | ||
|
||
StringBuilder sb = new StringBuilder(); | ||
while (sb.length() < 40_000_000) { | ||
sb.append(UUID.randomUUID()); | ||
} | ||
String in = sb.toString(); | ||
byte[] bytes = s.serialize(in); | ||
String out = s.deserialize(bytes, String.class); | ||
assertThat(out).isEqualTo(in); | ||
} | ||
|
||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...c/main/resources/META-INF/native-image/com.arangodb/http-protocol/native-image.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
Args=\ | ||
-H:ResourceConfigurationResources=${.}/resource-config-spi.json \ | ||
-H:ReflectionConfigurationResources=${.}/reflect-config-spi.json | ||
-H:ReflectionConfigurationResources=${.}/reflect-config-spi.json,${.}/reflect-config-serde.json |
Oops, something went wrong.