In einem Projekt, das mit Proguard (mit dem Gradle -Plugin) verschleiert wird, habe ich viel Serialisierung/Deserialisierung mit Jackson. Ich habe festgestellt, dass in den verschleierten Builds bestimmte Arten der Serialisierung polymorpher Typen die Typinformationen weglassen ), was während der Deserialisierung ein sehr seltsames Verhalten verursacht. unoBfuscated Code:
{
"owner" : "Jay Leno",
"cars" : [ {
"type" : "Corvette",
"name" : "Corvette",
"year" : 1963
}, {
"type" : "Aztek",
"name" : "Ugly",
"year" : 2003
} ]
}
< /code>
Hier ist die Ausgabe des genauen Codes nach dem Durchlauf von Proguard: < /p>
{
"owner" : "Jay Leno",
"cars" : [ {
"a" : 1963,
"name" : "Corvette"
}, {
"a" : 2003,
"name" : "Ugly"
} ]
}
Beachten Sie die Eigenschaft "Typ" in den Array -Elementen im verschleierten Formular. Dies veranlasst Jackson, diese Objekte falsch zu deserialisieren. Tut mir leid, dass ich so viel Code in eine Frage aufgenommen habe, aber das ist so minimal, wie ich ihn bekommen und trotzdem den Kontext und das Problem demonstrieren kann. Projekt. < /p>
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Corvette.class),
@JsonSubTypes.Type(value = Aztek.class)
})
public abstract class CarModel {
public abstract String getName();
public abstract int getYear();
}
@Getter
@AllArgsConstructor
@ToString
public class Corvette extends CarModel {
private int year;
@JsonCreator
public Corvette(@JsonProperty("name") String name, @JsonProperty("year") int year) {
this.year = year;
}
@Override
@ToString.Include
public String getName() {
return "Corvette";
}
}
@Getter
@Setter
@AllArgsConstructor
@ToString
public class Aztek extends CarModel {
private int year;
@JsonCreator
public Aztek(@JsonProperty("name") String name, @JsonProperty("year") int year) {
this.year = year;
}
@Override
@ToString.Include
public String getName() {
return "Ugly";
}
}
@Getter
public class Inventory {
private String owner;
private List cars;
@JsonCreator
public Inventory(@JsonProperty("owner") String owner, @JsonProperty("cars") List cars) {
this.owner = owner;
this.cars = cars;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder("Inventory [");
builder.append("owner=")
.append(owner)
.append(", cars=");
builder.append("]");
return builder.toString();
}
}
public class JacksonPolymorphicSerialization {
private final static ObjectMapper JSONMapper =
JsonMapper.builder()
.configure(DEFAULT_VIEW_INCLUSION, false)
.configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
.serializationInclusion(Include.NON_ABSENT)
.build();
private static final ObjectReader JSONReader = JSONMapper.readerFor(Inventory.class);
private static final ObjectWriter JSONWriter = JSONMapper.writerFor(Inventory.class).withDefaultPrettyPrinter();
public static void main(String[] args) throws JacksonException {
Corvette corvette = new Corvette(1963);
Aztek aztek = new Aztek(2003);
Inventory inventory = new Inventory("Jay Leno", List.of(corvette, aztek));
String json = JSONWriter.writeValueAsString(inventory);
System.out.println("Serialized form:\n" + json);
System.out.println();
inventory = JSONReader.readValue(json);
System.out.println("Deserialized object: " + inventory);
}
}
< /code>
Hier ist die Gradle-Build-Datei < /p>
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.guardsquare:proguard-gradle:7.6.1'
}
}
plugins {
id 'java'
id "io.freefair.lombok" version "8.12.1"
}
repositories {
mavenCentral()
}
def appMainClass = 'rizzo.test.JacksonPolymorphicSerialization'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
jar {
duplicatesStrategy = 'exclude'
manifest {
attributes 'Main-Class': "${appMainClass}"
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
dependencies {
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.2'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.18.2'
}
task proguard(type: proguard.gradle.ProGuardTask) {
dependsOn classes
verbose
printmapping "${buildDir}/proguard-mapping.txt"
injars "${buildDir}/classes/java/main"
outjars "${buildDir}/classes/obfuscated/"
libraryjars "${System.getProperty('java.home')}/jmods/java.base.jmod", jarfilter: '!**.jar', filter: '!module-info.class'
libraryjars "${System.getProperty('java.home')}/jmods/java.logging.jmod", jarfilter: '!**.jar', filter: '!module-info.class'
libraryjars "${System.getProperty('java.home')}/jmods/java.desktop.jmod", jarfilter: '!**.jar', filter: '!module-info.class'
libraryjars "${System.getProperty('java.home')}/jmods/java.xml.jmod", jarfilter: '!**.jar', filter: '!module-info.class'
libraryjars "${System.getProperty('java.home')}/jmods/java.sql.jmod", jarfilter: '!**.jar', filter: '!module-info.class'
// This will contain the app dependencies.
libraryjars sourceSets.main.compileClasspath
keepdirectories
// Preserve getters and setters
keepclassmembers 'class * { \
** get*(); \
void set*(***); \
}'
// Keep the main class entry point.
keep "public class ${appMainClass} { \
public static void main(java.lang.String[]); \
}"
// This helps produce useful stack traces (see https://www.guardsquare.com/manual/configuration/examples#stacktrace)
renamesourcefileattribute 'SourceFile'
keepattributes '*Annotation*,EnclosingMethod,SourceFile,LineNumberTable'
doLast {
delete "${buildDir}/classes/java/main"
copy {
from "${buildDir}/classes/obfuscated/"
into "${buildDir}/classes/java/main"
}
}
}
run ./gradlew jar Um zu erstellen, erhalten Sie ein normales (nicht oBfuscated) Glas. Run ./gradlew proguard jar und das resultierende Glas wird verschleiert. In jedem Fall können Sie mit Java -Jar ...
hier rennen. p>
> java -jar build/libs/ProguardJacksonTest.jar
Serialized form:
{
"owner" : "Jay Leno",
"cars" : [ {
"type" : "Corvette",
"name" : "Corvette",
"year" : 1963
}, {
"type" : "Aztek",
"name" : "Ugly",
"year" : 2003
} ]
}
First cars element is of type class rizzo.test.Corvette
Deserialized object: Inventory [owner=Jay Leno, cars=]
< /code>
Ausgabe unter Verwendung des verschleierten Builds: < /p>
> java -jar build/libs/ProguardJacksonTest.jar
Serialized form:
{
"owner" : "Jay Leno",
"cars" : [ {
"a" : 1963,
"name" : "Corvette"
}, {
"a" : 2003,
"name" : "Ugly"
} ]
}
Exception in thread "main" java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class rizzo.test.b (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; rizzo.test.b is in unnamed module of loader 'app')
at rizzo.test.d.toString(SourceFile:29)
at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453)
at java.base/java.lang.StringConcatHelper.simpleConcat(StringConcatHelper.java:408)
at rizzo.test.JacksonPolymorphicSerialization.main(SourceFile:38)
Die ClassCastException gibt an, dass die CARS -Liste tatsächlich mit LinkedHasMap -Instanzen anstelle von Carmodel -Instanzen so hoch ist. Aber ich denke, das macht angesichts des serialisierten Formulars, in dem Informationen fehlen, sinnvoll. Ich nehme an, Jackson hat das nur in Karten deserialisiert, da es nicht den tatsächlichen erwarteten Typ zur Laufzeit hat (danke, sooopid Typ -Löschung!). < BR /> Die eigentliche Frage ist, warum Jackson die Typinformationen aus dem serialisierten Form aus lässt, wenn der Code verschleiert wurde, und was kann ich dagegen tun? < /p>
In einem Projekt, das mit Proguard (mit dem Gradle -Plugin) verschleiert wird, habe ich viel Serialisierung/Deserialisierung mit Jackson. Ich habe festgestellt, dass in den verschleierten Builds bestimmte Arten der Serialisierung polymorpher Typen die Typinformationen weglassen ), was während der Deserialisierung ein sehr seltsames Verhalten verursacht. unoBfuscated Code: [code]{ "owner" : "Jay Leno", "cars" : [ { "type" : "Corvette", "name" : "Corvette", "year" : 1963 }, { "type" : "Aztek", "name" : "Ugly", "year" : 2003 } ] } < /code> Hier ist die Ausgabe des genauen Codes nach dem Durchlauf von Proguard: < /p> { "owner" : "Jay Leno", "cars" : [ { "a" : 1963, "name" : "Corvette" }, { "a" : 2003, "name" : "Ugly" } ] } [/code] Beachten Sie die Eigenschaft "Typ" in den Array -Elementen im verschleierten Formular. Dies veranlasst Jackson, diese Objekte falsch zu deserialisieren. Tut mir leid, dass ich so viel Code in eine Frage aufgenommen habe, aber das ist so minimal, wie ich ihn bekommen und trotzdem den Kontext und das [url=viewtopic.php?t=11587]Problem[/url] demonstrieren kann. Projekt. < /p> [code]@JsonAutoDetect(fieldVisibility = Visibility.ANY) @JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = Corvette.class), @JsonSubTypes.Type(value = Aztek.class) }) public abstract class CarModel {
public abstract String getName(); public abstract int getYear(); }
@Getter @AllArgsConstructor @ToString public class Corvette extends CarModel {
private int year;
@JsonCreator public Corvette(@JsonProperty("name") String name, @JsonProperty("year") int year) { this.year = year; }
@Override @ToString.Include public String getName() { return "Corvette"; } }
@Getter @Setter @AllArgsConstructor @ToString public class Aztek extends CarModel {
private int year;
@JsonCreator public Aztek(@JsonProperty("name") String name, @JsonProperty("year") int year) { this.year = year; }
@Override @ToString.Include public String getName() { return "Ugly"; } }
@Getter public class Inventory {
private String owner; private List cars;
@JsonCreator public Inventory(@JsonProperty("owner") String owner, @JsonProperty("cars") List cars) { this.owner = owner; this.cars = cars; }
@Override public String toString() { StringBuilder builder = new StringBuilder("Inventory ["); builder.append("owner=") .append(owner) .append(", cars=");
// Keep the main class entry point. keep "public class ${appMainClass} { \ public static void main(java.lang.String[]); \ }"
// This helps produce useful stack traces (see https://www.guardsquare.com/manual/configuration/examples#stacktrace) renamesourcefileattribute 'SourceFile' keepattributes '*Annotation*,EnclosingMethod,SourceFile,LineNumberTable'
doLast { delete "${buildDir}/classes/java/main" copy { from "${buildDir}/classes/obfuscated/" into "${buildDir}/classes/java/main" }
} }
[/code] run ./gradlew jar Um zu erstellen, erhalten Sie ein normales (nicht oBfuscated) Glas. Run ./gradlew proguard jar und das resultierende Glas wird verschleiert. In jedem Fall können Sie mit Java -Jar ... hier rennen. p> [code]> java -jar build/libs/ProguardJacksonTest.jar Serialized form: { "owner" : "Jay Leno", "cars" : [ { "type" : "Corvette", "name" : "Corvette", "year" : 1963 }, { "type" : "Aztek", "name" : "Ugly", "year" : 2003 } ] }
First cars element is of type class rizzo.test.Corvette Deserialized object: Inventory [owner=Jay Leno, cars=] < /code> Ausgabe unter Verwendung des verschleierten Builds: < /p> > java -jar build/libs/ProguardJacksonTest.jar Serialized form: { "owner" : "Jay Leno", "cars" : [ { "a" : 1963, "name" : "Corvette" }, { "a" : 2003, "name" : "Ugly" } ] }
Exception in thread "main" java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class rizzo.test.b (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; rizzo.test.b is in unnamed module of loader 'app') at rizzo.test.d.toString(SourceFile:29) at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453) at java.base/java.lang.StringConcatHelper.simpleConcat(StringConcatHelper.java:408) at rizzo.test.JacksonPolymorphicSerialization.main(SourceFile:38) [/code] Die ClassCastException gibt an, dass die CARS -Liste tatsächlich mit LinkedHasMap -Instanzen anstelle von Carmodel -Instanzen so hoch ist. Aber ich denke, das macht angesichts des serialisierten Formulars, in dem Informationen fehlen, sinnvoll. Ich nehme an, Jackson hat das nur in Karten deserialisiert, da es nicht den tatsächlichen erwarteten Typ zur Laufzeit hat (danke, sooopid Typ -Löschung!). < BR /> Die eigentliche Frage ist, warum Jackson die Typinformationen aus dem serialisierten Form aus lässt, wenn der Code verschleiert wurde, und was kann ich dagegen tun? < /p>
In einem Projekt, das mit Proguard (mit dem Gradle -Plugin) verschleiert wird, habe ich viel Serialisierung/Deserialisierung mit Jackson. Ich habe festgestellt, dass in den verschleierten Builds...
im folgenden Code, o .AccountEnabled hat bool wob br /> ohne den expliziten gegossenen zu bool? erhalte ich den folgenden Fehler:
'bool' does not contain a definition for 'ShouldBe' and the best...
SerializeDateTime Methode gibt die DateTime in Millisekunden zurück. Ich möchte, dass er sich an Mikrosekunden wendet. SerializedAtetime Methode wie folgt:
Ich verwende JSONDEVIVIVETTYPE für polymorphe Modelle im .NET -Kern und möchte eine korrekte Bindung im Controller sicherstellen. Senden Sie eine JSON -Nutzlast an diesen Endpunkt. Der korrekte...
Ich habe eine abstrakte Klasse, aus der Unterklassen abgeleitet werden. Die konkreten Implementierungen sollten eine Enum -Klasse enthalten, die einen Satz benannter Konstanten enthält.
from enum...