From be43dbfdcc61f8d98ed0ca8e31c4d8e5cf4285b9 Mon Sep 17 00:00:00 2001 From: AterAnimAvis Date: Wed, 10 Apr 2024 16:22:12 +0100 Subject: [PATCH] Add io-jackson --- README.md | 18 ++- gradle/libs.versions.toml | 2 + io-jackson/build.gradle | 19 +++ .../feather/io/jackson/FeatherModule.java | 33 ++++++ .../feather/io/jackson/modules/MDCModule.java | 44 +++++++ .../io/jackson/modules/MetadataModule.java | 32 +++++ .../jackson/modules/OffsetDateTimeModule.java | 26 ++++ .../jackson/modules/SimpleVersionModule.java | 17 +++ .../datetime/OffsetDateTimeDeserializer.java | 22 ++++ .../datetime/OffsetDateTimeSerializer.java | 24 ++++ .../modules/mdc/ClassDataDeserializer.java | 64 ++++++++++ .../modules/mdc/ClassDataSerializer.java | 73 ++++++++++++ .../modules/mdc/FieldDataDeserializer.java | 57 +++++++++ .../modules/mdc/FieldDataSerializer.java | 45 +++++++ .../modules/mdc/MethodDataDeserializer.java | 64 ++++++++++ .../modules/mdc/MethodDataSerializer.java | 59 +++++++++ .../modules/mdc/PackageDataDeserializer.java | 54 +++++++++ .../modules/mdc/PackageDataSerializer.java | 23 ++++ .../mdc/ParameterDataDeserializer.java | 53 +++++++++ .../modules/mdc/ParameterDataSerializer.java | 45 +++++++ ...ionedMappingDataContainerDeserializer.java | 63 ++++++++++ ...rsionedMappingDataContainerSerializer.java | 24 ++++ .../BouncingTargetMetadataDeserializer.java | 44 +++++++ .../BouncingTargetMetadataSerializer.java | 23 ++++ .../metadata/ClassMetadataDeserializer.java | 109 +++++++++++++++++ .../metadata/ClassMetadataSerializer.java | 33 ++++++ .../metadata/FieldMetadataDeserializer.java | 72 +++++++++++ .../metadata/FieldMetadataSerializer.java | 27 +++++ .../metadata/MethodMetadataDeserializer.java | 112 ++++++++++++++++++ .../metadata/MethodMetadataSerializer.java | 35 ++++++ .../modules/metadata/NamedDeserializer.java | 36 ++++++ .../modules/metadata/NamedSerializer.java | 27 +++++ .../metadata/RecordMetadataDeserializer.java | 61 ++++++++++ .../metadata/RecordMetadataSerializer.java | 24 ++++ .../metadata/ReferenceDeserializer.java | 65 ++++++++++ .../modules/metadata/ReferenceSerializer.java | 25 ++++ .../metadata/SourceMetadataDeserializer.java | 63 ++++++++++ .../metadata/SourceMetadataSerializer.java | 24 ++++ .../version/SimpleVersionDeserializer.java | 17 +++ .../version/SimpleVersionSerializer.java | 20 ++++ .../feather/io/jackson/util/BaseModule.java | 67 +++++++++++ .../feather/io/jackson/util/CommonTypes.java | 81 +++++++++++++ .../feather/io/jackson/util/Jackson.java | 35 ++++++ .../jackson/MDCJacksonAdapterFactoryTest.java | 49 ++++++++ .../jackson/MetadataAdapterFactoryTest.java | 37 ++++++ .../io/jackson/OffsetDateTimeAdapterTest.java | 22 ++++ .../io/jackson/SimpleVersionAdapterTest.java | 18 +++ .../feather/io/jackson/JacksonTest.java | 67 +++++++++++ .../io/jackson/spi/JacksonAdapterFactory.java | 49 ++++++++ ...g.parchmentmc.feather.spi.IOAdapterFactory | 1 + io-tests/build.gradle | 3 + .../feather/io/tests/AdapterPresenceTest.java | 2 +- settings.gradle | 2 + 53 files changed, 2109 insertions(+), 2 deletions(-) create mode 100644 io-jackson/build.gradle create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/FeatherModule.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/MDCModule.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/MetadataModule.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/OffsetDateTimeModule.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/SimpleVersionModule.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/datetime/OffsetDateTimeDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/datetime/OffsetDateTimeSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ClassDataDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ClassDataSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/FieldDataDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/FieldDataSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/MethodDataDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/MethodDataSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/PackageDataDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/PackageDataSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ParameterDataDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ParameterDataSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/VersionedMappingDataContainerDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/VersionedMappingDataContainerSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/BouncingTargetMetadataDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/BouncingTargetMetadataSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ClassMetadataDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ClassMetadataSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/FieldMetadataDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/FieldMetadataSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/MethodMetadataDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/MethodMetadataSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/NamedDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/NamedSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/RecordMetadataDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/RecordMetadataSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ReferenceDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ReferenceSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/SourceMetadataDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/SourceMetadataSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/version/SimpleVersionDeserializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/version/SimpleVersionSerializer.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/BaseModule.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/CommonTypes.java create mode 100644 io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/Jackson.java create mode 100644 io-jackson/src/test/java/org/parchment/feather/io/jackson/MDCJacksonAdapterFactoryTest.java create mode 100644 io-jackson/src/test/java/org/parchment/feather/io/jackson/MetadataAdapterFactoryTest.java create mode 100644 io-jackson/src/test/java/org/parchment/feather/io/jackson/OffsetDateTimeAdapterTest.java create mode 100644 io-jackson/src/test/java/org/parchment/feather/io/jackson/SimpleVersionAdapterTest.java create mode 100644 io-jackson/src/testFixtures/java/org/parchmentmc/feather/io/jackson/JacksonTest.java create mode 100644 io-jackson/src/testFixtures/java/org/parchmentmc/feather/io/jackson/spi/JacksonAdapterFactory.java create mode 100644 io-jackson/src/testFixtures/resources/META-INF/services/org.parchmentmc.feather.spi.IOAdapterFactory diff --git a/README.md b/README.md index 52e4dc7..db6077d 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ There are five subprojects within the repository: - **`core`** - the main data interfaces and implementations (immutables and builders). - **`io-gson`** - JSON adapters for the [Gson](https://github.com/google/gson) library - **`io-moshi`** - JSON adapters for the [Moshi](https://github.com/square/moshi) library. +- **`io-jackson`** - JSON adapters for the [Jackson](https://github.com/FasterXML/jackson-core) library. - **`io-proguard`** - parsing for ProGuard mapping files - **`utils`** - miscellaneous utilities not fit for inclusion in the core library @@ -31,6 +32,7 @@ dependencies { implementation "org.parchmentmc:feather:${feather_version}" implementation "org.parchmentmc.feather:io-gson:${feather_version}" // For the Gson adapters implementation "org.parchmentmc.feather:io-moshi:${feather_version}" // For the Moshi adapters + implementation "org.parchmentmc.feather:io-jackson:${feather_version}" // For the Jackson adapters implementation "org.parchmentmc.feather:io-proguard:${feather_version}" // For the ProGuard parser implementation "org.parchmentmc.feather:utils:${feather_version}" // For the misc. utilities } @@ -38,7 +40,7 @@ dependencies { ### The IO Libraries -Feather offers JSON adapters for two JSON parsing libraries: Gson and Moshi. +Feather offers JSON adapters for three JSON parsing libraries: Gson, Moshi and Jackson. ```java class UsingGson { @@ -68,6 +70,20 @@ class UsingMoshi { .add(new OffsetDateTimeAdapter()) .create(); } + +class UsingJackson { + final ObjectMapper jackson = new ObjectMapper() + // Required for `MappingDataContainer` and inner data classes + .registerModule(new MDCModule()) // Automatically adds `SimpleVersionModule` + // Required for `MappingDataContainer`s and `SourceMetadata` + .registerModule(new SimpleVersionModule()) + // Required for the metadata classes (`SourceMetadata`, `MethodReference`, etc.) and `Named` + .registerModule(new MetadataModule()) // Automatically adds `SimpleVersionModule` + // Required for parsing manifests: `LauncherManifest`, `VersionManifest`, and their inner data classes + .registerModule(new OffsetDateTimeModule()) + // Alternatively every Module combined. + .registerModule(new FeatherModule()); // Automatically adds `MDCModule`, `SimpleVersionModule`, `MetadataModule` and `OffsetDateTimeModule` +} ``` ## License diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ab9d448..31149ba 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,6 +5,7 @@ guava = '32.0.1-jre' # IO subproject dependencies gson = '2.10.1' +jackson = '2.16.0' moshi = '1.12.0' # Fixed to 1.12.0 because that's the last version written in Java # Test engine @@ -15,6 +16,7 @@ checker-qual = { module = 'org.checkerframework:checker-qual', version.ref = 'ch guava = { module = 'com.google.guava:guava', version.ref = 'guava' } gson = { module = 'com.google.code.gson:gson', version.ref = 'gson' } +jackson = { module = 'com.fasterxml.jackson.core:jackson-databind', version.ref = 'jackson' } moshi = { module = 'com.squareup.moshi:moshi', version.ref = 'moshi' } junit-api = { module = 'org.junit.jupiter:junit-jupiter-api', version.ref = 'junit' } diff --git a/io-jackson/build.gradle b/io-jackson/build.gradle new file mode 100644 index 0000000..99afb94 --- /dev/null +++ b/io-jackson/build.gradle @@ -0,0 +1,19 @@ +group = 'org.parchmentmc.feather' +archivesBaseName = 'io-jackson' + +dependencies { + api project(':feather') + api libs.jackson + + testFixturesApi testFixtures(project(':feather')) +} + +publishing { + publications.create("jacksonIO", MavenPublication) { + from components.java + pom { + name = "Feather IO - Jackson" + description = "Additional IO library for serializing JSON data objects using Jackson." + } + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/FeatherModule.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/FeatherModule.java new file mode 100644 index 0000000..5c064de --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/FeatherModule.java @@ -0,0 +1,33 @@ +package org.parchmentmc.feather.io.jackson; + +import com.fasterxml.jackson.core.Version; +import org.parchmentmc.feather.io.jackson.modules.MDCModule; +import org.parchmentmc.feather.io.jackson.modules.MetadataModule; +import org.parchmentmc.feather.io.jackson.modules.OffsetDateTimeModule; +import org.parchmentmc.feather.io.jackson.modules.SimpleVersionModule; +import org.parchmentmc.feather.io.jackson.util.BaseModule; + +import java.time.format.DateTimeFormatter; + +public class FeatherModule extends BaseModule { + + // TODO: Base it on Implementation-Version? We should probably be adding that in the META-INF + public static final Version VERSION = Version.unknownVersion(); + + public FeatherModule() { + this(false, DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + + /** + * @param ignoreNonDocumented whether this should ignore mapping data entries which have no javadocs. + * @param formatter formatter used to serialize and deserialize OffsetDateTime. + */ + public FeatherModule(boolean ignoreNonDocumented, DateTimeFormatter formatter) { + super("FeatherModule", FeatherModule.VERSION); + addDependency(new MDCModule(ignoreNonDocumented)); + addDependency(new MetadataModule()); + addDependency(new OffsetDateTimeModule(formatter)); + addDependency(new SimpleVersionModule()); + } + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/MDCModule.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/MDCModule.java new file mode 100644 index 0000000..6acdcb5 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/MDCModule.java @@ -0,0 +1,44 @@ +package org.parchmentmc.feather.io.jackson.modules; + +import org.parchmentmc.feather.io.jackson.FeatherModule; +import org.parchmentmc.feather.io.jackson.modules.mdc.*; +import org.parchmentmc.feather.io.jackson.util.BaseModule; +import org.parchmentmc.feather.mapping.MappingDataContainer; +import org.parchmentmc.feather.mapping.VersionedMappingDataContainer; + +public class MDCModule extends BaseModule { + + private final boolean ignoreNonDocumented; + + public MDCModule() { + this(false); + } + + /** + * @param ignoreNonDocumented whether this should ignore mapping data entries which have no javadocs. + */ + public MDCModule(boolean ignoreNonDocumented) { + super("Feather$MDC", FeatherModule.VERSION); + addDependency(new SimpleVersionModule()); + + addSerializer(VersionedMappingDataContainer.class, new VersionedMappingDataContainerSerializer()); + addDeserializer(VersionedMappingDataContainer.class, new VersionedMappingDataContainerDeserializer()); + addSerializer(MappingDataContainer.PackageData.class, new PackageDataSerializer()); + addDeserializer(MappingDataContainer.PackageData.class, new PackageDataDeserializer()); + addSerializer(MappingDataContainer.ClassData.class, new ClassDataSerializer(ignoreNonDocumented)); + addDeserializer(MappingDataContainer.ClassData.class, new ClassDataDeserializer()); + addSerializer(MappingDataContainer.FieldData.class, new FieldDataSerializer(ignoreNonDocumented)); + addDeserializer(MappingDataContainer.FieldData.class, new FieldDataDeserializer()); + addSerializer(MappingDataContainer.MethodData.class, new MethodDataSerializer(ignoreNonDocumented)); + addDeserializer(MappingDataContainer.MethodData.class, new MethodDataDeserializer()); + addSerializer(MappingDataContainer.ParameterData.class, new ParameterDataSerializer(ignoreNonDocumented)); + addDeserializer(MappingDataContainer.ParameterData.class, new ParameterDataDeserializer()); + + this.ignoreNonDocumented = ignoreNonDocumented; + } + + public boolean isIgnoreNonDocumented() { + return ignoreNonDocumented; + } + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/MetadataModule.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/MetadataModule.java new file mode 100644 index 0000000..a791e81 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/MetadataModule.java @@ -0,0 +1,32 @@ +package org.parchmentmc.feather.io.jackson.modules; + +import org.parchmentmc.feather.io.jackson.FeatherModule; +import org.parchmentmc.feather.io.jackson.modules.metadata.*; +import org.parchmentmc.feather.io.jackson.util.BaseModule; +import org.parchmentmc.feather.metadata.*; +import org.parchmentmc.feather.named.Named; + +public class MetadataModule extends BaseModule { + + public MetadataModule() { + super("Feather$Metadata", FeatherModule.VERSION); + addDependency(new SimpleVersionModule()); + + addSerializer(Named.class, new NamedSerializer()); + addDeserializer(Named.class, new NamedDeserializer()); + addSerializer(SourceMetadata.class, new SourceMetadataSerializer()); + addDeserializer(SourceMetadata.class, new SourceMetadataDeserializer()); + addSerializer(ClassMetadata.class, new ClassMetadataSerializer()); + addDeserializer(ClassMetadata.class, new ClassMetadataDeserializer()); + addSerializer(FieldMetadata.class, new FieldMetadataSerializer()); + addDeserializer(FieldMetadata.class, new FieldMetadataDeserializer()); + addSerializer(MethodMetadata.class, new MethodMetadataSerializer()); + addDeserializer(MethodMetadata.class, new MethodMetadataDeserializer()); + addSerializer(Reference.class, new ReferenceSerializer()); + addDeserializer(Reference.class, new ReferenceDeserializer()); + addSerializer(BouncingTargetMetadata.class, new BouncingTargetMetadataSerializer()); + addDeserializer(BouncingTargetMetadata.class, new BouncingTargetMetadataDeserializer()); + addSerializer(RecordMetadata.class, new RecordMetadataSerializer()); + addDeserializer(RecordMetadata.class, new RecordMetadataDeserializer()); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/OffsetDateTimeModule.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/OffsetDateTimeModule.java new file mode 100644 index 0000000..ea60299 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/OffsetDateTimeModule.java @@ -0,0 +1,26 @@ +package org.parchmentmc.feather.io.jackson.modules; + +import org.parchmentmc.feather.io.jackson.FeatherModule; +import org.parchmentmc.feather.io.jackson.modules.datetime.OffsetDateTimeDeserializer; +import org.parchmentmc.feather.io.jackson.modules.datetime.OffsetDateTimeSerializer; +import org.parchmentmc.feather.io.jackson.util.BaseModule; + +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; + +public class OffsetDateTimeModule extends BaseModule { + + public OffsetDateTimeModule() { + this(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + + /** + * @param formatter formatter used to serialize and deserialize OffsetDateTime. + */ + public OffsetDateTimeModule(DateTimeFormatter formatter) { + super("Feather$OffsetDateTime", FeatherModule.VERSION); + addSerializer(OffsetDateTime.class, new OffsetDateTimeSerializer(formatter)); + addDeserializer(OffsetDateTime.class, new OffsetDateTimeDeserializer(formatter)); + } + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/SimpleVersionModule.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/SimpleVersionModule.java new file mode 100644 index 0000000..0e35bfa --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/SimpleVersionModule.java @@ -0,0 +1,17 @@ +package org.parchmentmc.feather.io.jackson.modules; + +import org.parchmentmc.feather.io.jackson.FeatherModule; +import org.parchmentmc.feather.io.jackson.modules.version.SimpleVersionDeserializer; +import org.parchmentmc.feather.io.jackson.modules.version.SimpleVersionSerializer; +import org.parchmentmc.feather.io.jackson.util.BaseModule; +import org.parchmentmc.feather.util.SimpleVersion; + +public class SimpleVersionModule extends BaseModule { + + public SimpleVersionModule() { + super("Feather$SimpleVersion", FeatherModule.VERSION); + addSerializer(SimpleVersion.class, new SimpleVersionSerializer()); + addDeserializer(SimpleVersion.class, new SimpleVersionDeserializer()); + } + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/datetime/OffsetDateTimeDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/datetime/OffsetDateTimeDeserializer.java new file mode 100644 index 0000000..6746d5f --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/datetime/OffsetDateTimeDeserializer.java @@ -0,0 +1,22 @@ +package org.parchmentmc.feather.io.jackson.modules.datetime; + +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer; + +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; + +public class OffsetDateTimeDeserializer extends FromStringDeserializer { + + private final DateTimeFormatter formatter; + + public OffsetDateTimeDeserializer(DateTimeFormatter formatter) { + super(OffsetDateTime.class); + this.formatter = formatter; + } + + @Override + protected OffsetDateTime _deserialize(String value, DeserializationContext ctxt) { + return OffsetDateTime.parse(value, formatter); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/datetime/OffsetDateTimeSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/datetime/OffsetDateTimeSerializer.java new file mode 100644 index 0000000..055f518 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/datetime/OffsetDateTimeSerializer.java @@ -0,0 +1,24 @@ +package org.parchmentmc.feather.io.jackson.modules.datetime; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer; + +import java.io.IOException; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; + +public class OffsetDateTimeSerializer extends StdScalarSerializer { + + private final DateTimeFormatter formatter; + + public OffsetDateTimeSerializer(DateTimeFormatter formatter) { + super(OffsetDateTime.class); + this.formatter = formatter; + } + + @Override + public void serialize(OffsetDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeString(formatter.format(value)); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ClassDataDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ClassDataDeserializer.java new file mode 100644 index 0000000..57932a3 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ClassDataDeserializer.java @@ -0,0 +1,64 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.CommonTypes; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.mapping.ImmutableMappingDataContainer; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public class ClassDataDeserializer extends StdDeserializer { + + public ClassDataDeserializer() { + super(MappingDataContainer.ClassData.class); + } + + @Override + public MappingDataContainer.ClassData deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + String name = null; + List javadoc = null; + Collection fields = null; + Collection methods = null; + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "name": + name = node.get(propertyName).asText(); + break; + case "javadoc": + javadoc = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.LIST_STRING); + break; + case "fields": + fields = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.COLLECTION_FIELD_DATA); + break; + case "methods": + methods = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.COLLECTION_METHOD_DATA); + break; + default: + // do nothing + break; + } + } + + if (name == null) throw new JsonParseException("Class name must not be null"); + if (javadoc == null) javadoc = Collections.emptyList(); + if (fields == null) fields = Collections.emptyList(); + if (methods == null) methods = Collections.emptyList(); + + return new ImmutableMappingDataContainer.ImmutableClassData(name, javadoc, fields, methods); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ClassDataSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ClassDataSerializer.java new file mode 100644 index 0000000..f3dc369 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ClassDataSerializer.java @@ -0,0 +1,73 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; +import java.util.Collection; + +public class ClassDataSerializer extends StdSerializer { + + private final boolean ignoreNonDocumented; + + public ClassDataSerializer(boolean ignoreNonDocumented) { + super(MappingDataContainer.ClassData.class); + this.ignoreNonDocumented = ignoreNonDocumented; + } + + public boolean shouldIgnoreClasses( + FieldDataSerializer fieldDataSerializer, + MethodDataSerializer methodDataSerializer, + ParameterDataSerializer parameterDataSerializer, + Collection values + ) { + return ignoreNonDocumented && values.stream().allMatch(classData -> this.shouldIgnoreClass( + fieldDataSerializer, + methodDataSerializer, + parameterDataSerializer, + classData + )); + } + + public boolean shouldIgnoreClass( + FieldDataSerializer fieldDataSerializer, + MethodDataSerializer methodDataSerializer, + ParameterDataSerializer parameterDataSerializer, + MappingDataContainer.ClassData value + ) { + if (!ignoreNonDocumented) return false; + if (!value.getJavadoc().isEmpty()) return false; + + boolean shouldIgnoreFields = fieldDataSerializer.shouldIgnoreFields(value.getFields()); + if (!shouldIgnoreFields) return false; + + boolean shouldIgnoreMethods = methodDataSerializer.shouldIgnoreMethods(parameterDataSerializer, value.getMethods()); + return shouldIgnoreMethods; + } + + @Override + public void serialize(MappingDataContainer.ClassData value, JsonGenerator gen, SerializerProvider provider) throws IOException { + final FieldDataSerializer fieldDataSerializer = Jackson.getSerializer(gen, provider, MappingDataContainer.FieldData.class, FieldDataSerializer.class); + final MethodDataSerializer methodDataSerializer = Jackson.getSerializer(gen, provider, MappingDataContainer.MethodData.class, MethodDataSerializer.class); + final ParameterDataSerializer packageDataSerializer = Jackson.getSerializer(gen, provider, MappingDataContainer.ParameterData.class, ParameterDataSerializer.class); + + if (shouldIgnoreClass(fieldDataSerializer, methodDataSerializer, packageDataSerializer, value)) { + gen.writeNull(); + return; + } + + gen.writeStartObject(); + gen.writePOJOField("name", value.getName()); + if (!value.getJavadoc().isEmpty()) gen.writePOJOField("javadoc", value.getJavadoc()); + if (!value.getFields().isEmpty()) gen.writePOJOField("fields", value.getFields()); + if (!value.getMethods().isEmpty()) gen.writePOJOField("methods", value.getMethods()); + gen.writeEndObject(); + } + + public boolean isIgnoreNonDocumented() { + return ignoreNonDocumented; + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/FieldDataDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/FieldDataDeserializer.java new file mode 100644 index 0000000..c162bec --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/FieldDataDeserializer.java @@ -0,0 +1,57 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.CommonTypes; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.mapping.ImmutableMappingDataContainer; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public class FieldDataDeserializer extends StdDeserializer { + + public FieldDataDeserializer() { + super(MappingDataContainer.FieldData.class); + } + + @Override + public MappingDataContainer.FieldData deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + String name = null; + String descriptor = null; + List javadoc = null; + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "name": + name = node.get(propertyName).asText(); + case "descriptor": + descriptor = node.get(propertyName).asText(); + break; + case "javadoc": + javadoc = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.LIST_STRING); + break; + default: + // do nothing + break; + } + } + + if (name == null) throw new JsonParseException("Field name must not be null"); + if (descriptor == null) throw new JsonParseException("Field descriptor must not be null"); + if (javadoc == null) javadoc = Collections.emptyList(); + + return new ImmutableMappingDataContainer.ImmutableFieldData(name, descriptor, javadoc); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/FieldDataSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/FieldDataSerializer.java new file mode 100644 index 0000000..b76e003 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/FieldDataSerializer.java @@ -0,0 +1,45 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; +import java.util.Collection; + +public class FieldDataSerializer extends StdSerializer { + + private final boolean ignoreNonDocumented; + + public FieldDataSerializer(boolean ignoreNonDocumented) { + super(MappingDataContainer.FieldData.class); + this.ignoreNonDocumented = ignoreNonDocumented; + } + + public boolean shouldIgnoreFields(Collection values) { + return ignoreNonDocumented && values.stream().allMatch(this::shouldIgnoreField); + } + + public boolean shouldIgnoreField(MappingDataContainer.FieldData value) { + return ignoreNonDocumented && value.getJavadoc().isEmpty(); + } + + @Override + public void serialize(MappingDataContainer.FieldData value, JsonGenerator gen, SerializerProvider provider) throws IOException { + if (shouldIgnoreField(value)) { + gen.writeNull(); + return; + } + + gen.writeStartObject(); + gen.writePOJOField("name", value.getName()); + gen.writePOJOField("descriptor", value.getDescriptor()); + if (!value.getJavadoc().isEmpty()) gen.writePOJOField("javadoc", value.getJavadoc()); + gen.writeEndObject(); + } + + public boolean isIgnoreNonDocumented() { + return ignoreNonDocumented; + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/MethodDataDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/MethodDataDeserializer.java new file mode 100644 index 0000000..09a9fd8 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/MethodDataDeserializer.java @@ -0,0 +1,64 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.CommonTypes; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.mapping.ImmutableMappingDataContainer; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public class MethodDataDeserializer extends StdDeserializer { + + public MethodDataDeserializer() { + super(MappingDataContainer.MethodData.class); + } + + @Override + public MappingDataContainer.MethodData deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + String name = null; + String descriptor = null; + List javadoc = null; + Collection parameters = null; + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "name": + name = node.get(propertyName).asText(); + break; + case "descriptor": + descriptor = node.get(propertyName).asText(); + break; + case "javadoc": + javadoc = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.LIST_STRING); + break; + case "parameters": + parameters = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.COLLECTION_PARAMETER_DATA); + break; + default: + // do nothing + break; + } + } + + if (name == null) throw new JsonParseException("Field name must not be null"); + if (descriptor == null) throw new JsonParseException("Field descriptor must not be null"); + if (javadoc == null) javadoc = Collections.emptyList(); + if (parameters == null) parameters = Collections.emptyList(); + + return new ImmutableMappingDataContainer.ImmutableMethodData(name, descriptor, javadoc, parameters); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/MethodDataSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/MethodDataSerializer.java new file mode 100644 index 0000000..9d3fbbf --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/MethodDataSerializer.java @@ -0,0 +1,59 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; +import java.util.Collection; + +public class MethodDataSerializer extends StdSerializer { + + private final boolean ignoreNonDocumented; + + public MethodDataSerializer(boolean ignoreNonDocumented) { + super(MappingDataContainer.MethodData.class); + this.ignoreNonDocumented = ignoreNonDocumented; + } + + public boolean shouldIgnoreMethods(ParameterDataSerializer parameterSerializer, Collection values) { + return ignoreNonDocumented && values.stream().allMatch(methodData -> this.shouldIgnoreMethod(parameterSerializer, methodData)); + } + + public boolean shouldIgnoreMethod(ParameterDataSerializer parameterSerializer, MappingDataContainer.MethodData value) { + return ignoreNonDocumented && value.getJavadoc().isEmpty() && parameterSerializer.shouldIgnoreParameters(value.getParameters()); + } + + @Override + public void serialize(MappingDataContainer.MethodData value, JsonGenerator gen, SerializerProvider provider) throws IOException { + JsonSerializer parameterSerializer = getJsonSerializer(gen, provider); + + if (shouldIgnoreMethod((ParameterDataSerializer) parameterSerializer, value)) { + gen.writeNull(); + return; + } + + gen.writeStartObject(); + gen.writePOJOField("name", value.getName()); + gen.writePOJOField("descriptor", value.getDescriptor()); + if (!value.getJavadoc().isEmpty()) gen.writePOJOField("javadoc", value.getJavadoc()); + if (!value.getParameters().isEmpty()) gen.writePOJOField("parameters", value.getParameters()); + gen.writeEndObject(); + } + + private static JsonSerializer getJsonSerializer(JsonGenerator gen, SerializerProvider provider) throws JsonMappingException, JsonGenerationException { + JsonSerializer parameterSerializer = provider.findValueSerializer(MappingDataContainer.ParameterData.class); + final boolean isParameterSerializer = parameterSerializer instanceof ParameterDataSerializer; + if (!isParameterSerializer) throw new JsonGenerationException("Could not get instance of ParameterDataSerializer", gen); + return parameterSerializer; + } + + public boolean isIgnoreNonDocumented() { + return ignoreNonDocumented; + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/PackageDataDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/PackageDataDeserializer.java new file mode 100644 index 0000000..3b01a52 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/PackageDataDeserializer.java @@ -0,0 +1,54 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.CommonTypes; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.mapping.ImmutableMappingDataContainer; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public class PackageDataDeserializer extends StdDeserializer { + + public PackageDataDeserializer() { + super(MappingDataContainer.PackageData.class); + } + + @Override + public MappingDataContainer.PackageData deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + String name = null; + List javadoc = null; + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "name": + name = node.get(propertyName).asText(); + break; + case "javadoc": + javadoc = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.LIST_STRING); + break; + default: + // do nothing + break; + } + } + + if (name == null) throw new JsonParseException("Package name must not be null"); + if (javadoc == null) javadoc = Collections.emptyList(); + + return new ImmutableMappingDataContainer.ImmutablePackageData(name, javadoc); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/PackageDataSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/PackageDataSerializer.java new file mode 100644 index 0000000..3a3aea6 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/PackageDataSerializer.java @@ -0,0 +1,23 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; + +public class PackageDataSerializer extends StdSerializer { + + public PackageDataSerializer() { + super(MappingDataContainer.PackageData.class); + } + + @Override + public void serialize(MappingDataContainer.PackageData value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeStartObject(); + gen.writePOJOField("name", value.getName()); + if (!value.getJavadoc().isEmpty()) gen.writePOJOField("javadoc", value.getJavadoc()); + gen.writeEndObject(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ParameterDataDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ParameterDataDeserializer.java new file mode 100644 index 0000000..396eb7e --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ParameterDataDeserializer.java @@ -0,0 +1,53 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.mapping.ImmutableMappingDataContainer; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; +import java.util.Iterator; + +public class ParameterDataDeserializer extends StdDeserializer { + + public ParameterDataDeserializer() { + super(MappingDataContainer.ParameterData.class); + } + + @Override + public MappingDataContainer.ParameterData deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + byte index = -1; //TODO: byte seems wrong it's signed iirc JVM supports unsigned 255 params + String name = null; + String javadoc = null; + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "index": + index = (byte) node.get(propertyName).asInt(); + break; + case "name": + name = node.get(propertyName).asText(); + break; + case "javadoc": + javadoc = node.get(propertyName).asText(); + break; + default: + // do nothing + break; + } + } + + if (index < 0) throw new JsonParseException("Parameter index must be present and positive"); + + return new ImmutableMappingDataContainer.ImmutableParameterData(index, name, javadoc); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ParameterDataSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ParameterDataSerializer.java new file mode 100644 index 0000000..e23a8b8 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/ParameterDataSerializer.java @@ -0,0 +1,45 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; +import java.util.Collection; + +public class ParameterDataSerializer extends StdSerializer { + + private final boolean ignoreNonDocumented; + + public ParameterDataSerializer(boolean ignoreNonDocumented) { + super(MappingDataContainer.ParameterData.class); + this.ignoreNonDocumented = ignoreNonDocumented; + } + + public boolean shouldIgnoreParameters(Collection values) { + return ignoreNonDocumented && values.stream().allMatch(this::shouldIgnoreParameter); + } + + public boolean shouldIgnoreParameter(MappingDataContainer.ParameterData value) { + return ignoreNonDocumented && value.getName() == null && value.getJavadoc() == null; + } + + @Override + public void serialize(MappingDataContainer.ParameterData value, JsonGenerator gen, SerializerProvider provider) throws IOException { + if (shouldIgnoreParameter(value)) { + gen.writeNull(); + return; + } + + gen.writeStartObject(); + gen.writePOJOField("index", value.getIndex()); + if (value.getName() != null) gen.writePOJOField("name", value.getName()); + if (value.getJavadoc() != null) gen.writePOJOField("javadoc", value.getJavadoc()); + gen.writeEndObject(); + } + + public boolean isIgnoreNonDocumented() { + return ignoreNonDocumented; + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/VersionedMappingDataContainerDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/VersionedMappingDataContainerDeserializer.java new file mode 100644 index 0000000..8f9b86a --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/VersionedMappingDataContainerDeserializer.java @@ -0,0 +1,63 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.CommonTypes; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.mapping.ImmutableVersionedMappingDataContainer; +import org.parchmentmc.feather.mapping.MappingDataContainer; +import org.parchmentmc.feather.mapping.VersionedMappingDataContainer; +import org.parchmentmc.feather.util.SimpleVersion; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +public class VersionedMappingDataContainerDeserializer extends StdDeserializer { + + public VersionedMappingDataContainerDeserializer() { + super(VersionedMappingDataContainer.class); + } + + @Override + public VersionedMappingDataContainer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + SimpleVersion version = null; + Collection packages = null; + Collection classes = null; + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "version": + version = ctxt.readTreeAsValue(node.get(propertyName), SimpleVersion.class); + if (version != null && !version.isCompatibleWith(VersionedMappingDataContainer.CURRENT_FORMAT)) + throw new JsonParseException("Version " + version + " is incompatible with current version " + + VersionedMappingDataContainer.CURRENT_FORMAT); + break; + case "packages": + packages = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.COLLECTION_PACKAGE_DATA); + break; + case "classes": + classes = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.COLLECTION_CLASS_DATA); + break; + default: + // do nothing + break; + } + } + + if (packages == null) packages = Collections.emptyList(); + if (classes == null) classes = Collections.emptyList(); + if (version == null) throw new JsonParseException("No version found"); + + return new ImmutableVersionedMappingDataContainer(version, packages, classes); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/VersionedMappingDataContainerSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/VersionedMappingDataContainerSerializer.java new file mode 100644 index 0000000..ee12127 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/mdc/VersionedMappingDataContainerSerializer.java @@ -0,0 +1,24 @@ +package org.parchmentmc.feather.io.jackson.modules.mdc; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.mapping.VersionedMappingDataContainer; + +import java.io.IOException; + +public class VersionedMappingDataContainerSerializer extends StdSerializer { + + public VersionedMappingDataContainerSerializer() { + super(VersionedMappingDataContainer.class); + } + + @Override + public void serialize(VersionedMappingDataContainer value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeStartObject(); + gen.writePOJOField("version", value.getFormatVersion()); + gen.writePOJOField("packages", value.getPackages()); + gen.writePOJOField("classes", value.getClasses()); + gen.writeEndObject(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/BouncingTargetMetadataDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/BouncingTargetMetadataDeserializer.java new file mode 100644 index 0000000..44152be --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/BouncingTargetMetadataDeserializer.java @@ -0,0 +1,44 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.metadata.*; + +import java.io.IOException; +import java.util.Iterator; + +public class BouncingTargetMetadataDeserializer extends StdDeserializer { + + public BouncingTargetMetadataDeserializer() { + super(BouncingTargetMetadata.class); + } + + @Override + public BouncingTargetMetadata deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + final BouncingTargetMetadataBuilder builder = BouncingTargetMetadataBuilder.create(); + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "target": + builder.withTarget(ctxt.readTreeAsValue(node.get(propertyName), Reference.class)); + break; + case "owner": + builder.withOwner(ctxt.readTreeAsValue(node.get(propertyName), Reference.class)); + break; + default: + // do nothing + break; + } + } + + return builder.build(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/BouncingTargetMetadataSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/BouncingTargetMetadataSerializer.java new file mode 100644 index 0000000..47b502b --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/BouncingTargetMetadataSerializer.java @@ -0,0 +1,23 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.metadata.BouncingTargetMetadata; + +import java.io.IOException; + +public class BouncingTargetMetadataSerializer extends StdSerializer { + + public BouncingTargetMetadataSerializer() { + super(BouncingTargetMetadata.class); + } + + @Override + public void serialize(BouncingTargetMetadata value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeStartObject(); + if (value.getTarget().isPresent()) gen.writePOJOField("target", value.getTarget().get()); + if (value.getOwner().isPresent()) gen.writePOJOField("owner", value.getOwner().get()); + gen.writeEndObject(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ClassMetadataDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ClassMetadataDeserializer.java new file mode 100644 index 0000000..f1dd249 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ClassMetadataDeserializer.java @@ -0,0 +1,109 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.CommonTypes; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.metadata.*; +import org.parchmentmc.feather.named.Named; + +import java.io.IOException; +import java.util.Iterator; +import java.util.LinkedHashSet; + +public class ClassMetadataDeserializer extends StdDeserializer { + + public ClassMetadataDeserializer() { + super(ClassMetadata.class); + } + + @Override + public ClassMetadata deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + Named name = Named.empty(); + Named owner = Named.empty(); + int security = -1; + Named superName = Named.empty(); + LinkedHashSet interfaces = null; + LinkedHashSet fields = null; + LinkedHashSet methods = null; + LinkedHashSet records = null; + LinkedHashSet innerClasses = null; + Named signature = Named.empty(); + boolean isRecord = false; + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "name": + name = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "owner": + owner = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "security": + security = node.get(propertyName).asInt(); + break; + case "extends": + superName = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "implements": + interfaces = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.SET_NAMED); + break; + case "fields": + fields = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.SET_FIELD_METADATA); + break; + case "records": + records = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.SET_RECORD_METADATA); + break; + case "methods": + methods = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.SET_METHOD_METADATA); + break; + case "inner": + innerClasses = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.SET_CLASS_METADATA); + break; + case "signature": + signature = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "record": + isRecord = node.get(propertyName).asBoolean(); + break; + default: + // do nothing + break; + } + } + + if (name.isEmpty()) throw new JsonParseException("Class metadata name is not present or empty"); + // owner can be empty + if (security == -1) throw new JsonParseException("Class metadata security specification is not present"); + // superName can be empty + if (interfaces == null) methods = new LinkedHashSet<>(); + if (fields == null) fields = new LinkedHashSet<>(); + if (records == null) records = new LinkedHashSet<>(); + if (methods == null) methods = new LinkedHashSet<>(); + if (innerClasses == null) innerClasses = new LinkedHashSet<>(); + if (!records.isEmpty()) isRecord = true; + + return ClassMetadataBuilder.create() + .withSuperName(superName) + .withInterfaces(interfaces) + .withOwner(owner) + .withMethods(methods) + .withFields(fields) + .withInnerClasses(innerClasses) + .withName(name) + .withSecuritySpecifications(security) + .withSignature(signature) + .withRecords(records) + .withIsRecord(isRecord) + .build(); + } + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ClassMetadataSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ClassMetadataSerializer.java new file mode 100644 index 0000000..276d76e --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ClassMetadataSerializer.java @@ -0,0 +1,33 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.metadata.ClassMetadata; + +import java.io.IOException; + +public class ClassMetadataSerializer extends StdSerializer { + + public ClassMetadataSerializer() { + super(ClassMetadata.class); + } + + @Override + public void serialize(ClassMetadata value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeStartObject(); + gen.writePOJOField("name", value.getName()); + gen.writePOJOField("owner", value.getOwner()); + gen.writePOJOField("security", value.getSecuritySpecification()); + gen.writePOJOField("extends", value.getSuperName()); + gen.writePOJOField("implements", value.getInterfaces()); + gen.writePOJOField("fields", value.getFields()); + gen.writePOJOField("methods", value.getMethods()); + gen.writePOJOField("records", value.getRecords()); + gen.writePOJOField("inner", value.getInnerClasses()); + gen.writePOJOField("signature", value.getSignature()); + gen.writePOJOField("record", value.isRecord()); + gen.writeEndObject(); + } + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/FieldMetadataDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/FieldMetadataDeserializer.java new file mode 100644 index 0000000..ab8b29c --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/FieldMetadataDeserializer.java @@ -0,0 +1,72 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.metadata.FieldMetadata; +import org.parchmentmc.feather.metadata.FieldMetadataBuilder; +import org.parchmentmc.feather.named.Named; + +import java.io.IOException; +import java.util.Iterator; + +public class FieldMetadataDeserializer extends StdDeserializer { + + public FieldMetadataDeserializer() { + super(FieldMetadata.class); + } + + @Override + public FieldMetadata deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + Named name = Named.empty(); + Named owner = Named.empty(); + int security = -1; + Named descriptor = Named.empty(); + Named signature = Named.empty(); + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "name": + name = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "owner": + owner = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "security": + security = node.get(propertyName).asInt(); + break; + case "descriptor": + descriptor = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "signature": + signature = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + default: + // do nothing + break; + } + } + + if (name.isEmpty()) throw new JsonParseException("Field name is not present or empty"); + if (owner.isEmpty()) throw new JsonParseException("Field owner is not present or empty"); + if (security == -1) throw new JsonParseException("Field security specification is not present"); + if (descriptor.isEmpty()) throw new JsonParseException("Field descriptor is not present or empty"); + + return FieldMetadataBuilder.create() + .withOwner(owner) + .withName(name) + .withSecuritySpecification(security) + .withSignature(signature) + .withDescriptor(descriptor) + .build(); + } + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/FieldMetadataSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/FieldMetadataSerializer.java new file mode 100644 index 0000000..c9be0b6 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/FieldMetadataSerializer.java @@ -0,0 +1,27 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.metadata.FieldMetadata; + +import java.io.IOException; + +public class FieldMetadataSerializer extends StdSerializer { + + public FieldMetadataSerializer() { + super(FieldMetadata.class); + } + + @Override + public void serialize(FieldMetadata value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeStartObject(); + gen.writePOJOField("name", value.getName()); + gen.writePOJOField("owner", value.getOwner()); + gen.writePOJOField("security", value.getSecuritySpecification()); + gen.writePOJOField("descriptor", value.getDescriptor()); + gen.writePOJOField("signature", value.getSignature()); + gen.writeEndObject(); + } + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/MethodMetadataDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/MethodMetadataDeserializer.java new file mode 100644 index 0000000..232284e --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/MethodMetadataDeserializer.java @@ -0,0 +1,112 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.CommonTypes; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.metadata.BouncingTargetMetadata; +import org.parchmentmc.feather.metadata.MethodMetadata; +import org.parchmentmc.feather.metadata.MethodMetadataBuilder; +import org.parchmentmc.feather.metadata.Reference; +import org.parchmentmc.feather.named.Named; + +import java.io.IOException; +import java.util.Iterator; +import java.util.LinkedHashSet; + +public class MethodMetadataDeserializer extends StdDeserializer { + + public MethodMetadataDeserializer() { + super(MethodMetadata.class); + } + + @Override + public MethodMetadata deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + Named name = Named.empty(); + Named owner = Named.empty(); + int security = -1; + Named descriptor = Named.empty(); + Named signature = Named.empty(); + boolean lambda = false; + BouncingTargetMetadata bouncingTarget = null; + LinkedHashSet overrides = null; + int startLine = 0; + int endLine = 0; + Reference parent = null; + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "name": + name = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "owner": + owner = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "security": + security = node.get(propertyName).asInt(); + break; + case "descriptor": + descriptor = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "signature": + signature = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "lambda": + lambda = node.get(propertyName).asBoolean(); + break; + case "bouncingTarget": + bouncingTarget = ctxt.readTreeAsValue(node.get(propertyName), BouncingTargetMetadata.class); + break; + case "parent": + parent = ctxt.readTreeAsValue(node.get(propertyName), Reference.class); + break; + case "overrides": + overrides = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.SET_REFERENCE); + break; + case "startLine": + startLine = node.get(propertyName).asInt(); + break; + case "endLine": + endLine = node.get(propertyName).asInt(); + break; + default: + // do nothing + break; + } + } + + if (name.isEmpty()) throw new JsonParseException("Method metadata name is not present or empty"); + if (owner.isEmpty()) throw new JsonParseException("Method metadata owner is not present or empty"); + if (descriptor.isEmpty()) throw new JsonParseException("Method metadata descriptor is not present or empty"); + if (security == -1) throw new JsonParseException("Method metadata security specification is not present"); + // lambda is a primitive + // bouncingTarget can be null + if (overrides == null) overrides = new LinkedHashSet<>(); + if (startLine < 0) throw new JsonParseException("Method metadata contains negative start line"); + if (endLine < 0) throw new JsonParseException("Method metadata contains negative end line"); + if (endLine < startLine) throw new JsonParseException("Method metadata contains end before start"); + + return MethodMetadataBuilder.create() + .withBouncingTarget(bouncingTarget) + .withName(name) + .withOwner(owner) + .withDescriptor(descriptor) + .withSignature(signature) + .withSecuritySpecification(security) + .withParent(parent) + .withOverrides(overrides) + .withStartLine(startLine) + .withEndLine(endLine) + .withLambda(lambda) + .build(); + } + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/MethodMetadataSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/MethodMetadataSerializer.java new file mode 100644 index 0000000..9407c13 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/MethodMetadataSerializer.java @@ -0,0 +1,35 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.metadata.MethodMetadata; + +import java.io.IOException; + +public class MethodMetadataSerializer extends StdSerializer { + + public MethodMetadataSerializer() { + super(MethodMetadata.class); + } + + @Override + public void serialize(MethodMetadata value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeStartObject(); + gen.writePOJOField("name", value.getName()); + gen.writePOJOField("owner", value.getOwner()); + gen.writePOJOField("security", value.getSecuritySpecification()); + gen.writePOJOField("descriptor", value.getDescriptor()); + gen.writePOJOField("signature", value.getSignature()); + gen.writePOJOField("lambda", value.isLambda()); + + if (value.getBouncingTarget().isPresent()) gen.writePOJOField("bouncingTarget", value.getBouncingTarget().get()); + if (value.getParent().isPresent()) gen.writePOJOField("parent", value.getParent().get()); + if (!value.getOverrides().isEmpty()) gen.writePOJOField("overrides", value.getOverrides()); + if (value.getStartLine().isPresent()) gen.writePOJOField("startLine", value.getStartLine().orElse(0)); + if (value.getEndLine().isPresent()) gen.writePOJOField("endLine", value.getEndLine().orElse(0)); + + gen.writeEndObject(); + } + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/NamedDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/NamedDeserializer.java new file mode 100644 index 0000000..a25f5a8 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/NamedDeserializer.java @@ -0,0 +1,36 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.named.Named; +import org.parchmentmc.feather.named.NamedBuilder; + +import java.io.IOException; +import java.util.Iterator; + +public class NamedDeserializer extends StdDeserializer { + + public NamedDeserializer() { + super(Named.class); + } + + @Override + public Named deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + final NamedBuilder builder = NamedBuilder.create(); + + final Iterator schemas = node.fieldNames(); + while (schemas.hasNext()) { + final String schema = schemas.next(); + final String name = node.get(schema).asText(); + builder.with(schema, name); + } + + return builder.build(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/NamedSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/NamedSerializer.java new file mode 100644 index 0000000..b0440b2 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/NamedSerializer.java @@ -0,0 +1,27 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.named.Named; + +import java.io.IOException; +import java.util.Map; + +public class NamedSerializer extends StdSerializer { + + public NamedSerializer() { + super(Named.class); + } + + @Override + public void serialize(Named value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeStartObject(); + for (Map.Entry entry : value.getNames().entrySet()) { + final String schema = entry.getKey(); + final String name = entry.getValue(); + gen.writePOJOField(schema, name); + } + gen.writeEndObject(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/RecordMetadataDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/RecordMetadataDeserializer.java new file mode 100644 index 0000000..6e2a6be --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/RecordMetadataDeserializer.java @@ -0,0 +1,61 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.metadata.RecordMetadata; +import org.parchmentmc.feather.metadata.RecordMetadataBuilder; +import org.parchmentmc.feather.metadata.Reference; +import org.parchmentmc.feather.named.Named; + +import java.io.IOException; +import java.util.Iterator; + +public class RecordMetadataDeserializer extends StdDeserializer { + + public RecordMetadataDeserializer() { + super(RecordMetadata.class); + } + + @Override + public RecordMetadata deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + Named owner = Named.empty(); + Reference field = null; + Reference getter = null; + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "owner": + owner = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "field": + field = ctxt.readTreeAsValue(node.get(propertyName), Reference.class); + break; + case "getter": + getter = ctxt.readTreeAsValue(node.get(propertyName), Reference.class); + break; + default: + // do nothing + break; + } + } + + if (owner.isEmpty()) throw new JsonParseException("Field owner is not present or empty"); + if (field == null) throw new JsonParseException("Field field is not present or empty"); + if (getter == null) throw new JsonParseException("Field getter is not present or empty"); + + return RecordMetadataBuilder.create() + .withOwner(owner) + .withField(field) + .withGetter(getter) + .build(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/RecordMetadataSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/RecordMetadataSerializer.java new file mode 100644 index 0000000..e4ec35d --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/RecordMetadataSerializer.java @@ -0,0 +1,24 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.metadata.RecordMetadata; + +import java.io.IOException; + +public class RecordMetadataSerializer extends StdSerializer { + + public RecordMetadataSerializer() { + super(RecordMetadata.class); + } + + @Override + public void serialize(RecordMetadata value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeStartObject(); + gen.writePOJOField("owner", value.getOwner()); + gen.writePOJOField("field", value.getField()); + gen.writePOJOField("getter", value.getGetter()); + gen.writeEndObject(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ReferenceDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ReferenceDeserializer.java new file mode 100644 index 0000000..d307149 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ReferenceDeserializer.java @@ -0,0 +1,65 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.metadata.Reference; +import org.parchmentmc.feather.metadata.ReferenceBuilder; +import org.parchmentmc.feather.named.Named; + +import java.io.IOException; +import java.util.Iterator; + +public class ReferenceDeserializer extends StdDeserializer { + + public ReferenceDeserializer() { + super(Reference.class); + } + + @Override + public Reference deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + Named name = Named.empty(); + Named owner = Named.empty(); + Named descriptor = Named.empty(); + Named signature = Named.empty(); + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "name": + name = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "owner": + owner = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "descriptor": + descriptor = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + case "signature": + signature = ctxt.readTreeAsValue(node.get(propertyName), Named.class); + break; + default: + // do nothing + break; + } + } + + if (name.isEmpty()) throw new JsonParseException("Method reference name is not present"); + if (owner.isEmpty()) throw new JsonParseException("Method reference owner is not present"); + if (descriptor.isEmpty()) throw new JsonParseException("Method reference descriptor is not present"); + + return ReferenceBuilder.create() + .withOwner(owner) + .withName(name) + .withSignature(signature) + .withDescriptor(descriptor) + .build(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ReferenceSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ReferenceSerializer.java new file mode 100644 index 0000000..a1b333e --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/ReferenceSerializer.java @@ -0,0 +1,25 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.metadata.Reference; + +import java.io.IOException; + +public class ReferenceSerializer extends StdSerializer { + + public ReferenceSerializer() { + super(Reference.class); + } + + @Override + public void serialize(Reference value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeStartObject(); + gen.writePOJOField("name", value.getName()); + gen.writePOJOField("owner", value.getOwner()); + gen.writePOJOField("descriptor", value.getDescriptor()); + gen.writePOJOField("signature", value.getSignature()); + gen.writeEndObject(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/SourceMetadataDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/SourceMetadataDeserializer.java new file mode 100644 index 0000000..20d56b1 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/SourceMetadataDeserializer.java @@ -0,0 +1,63 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.parchmentmc.feather.io.jackson.util.CommonTypes; +import org.parchmentmc.feather.io.jackson.util.Jackson; +import org.parchmentmc.feather.metadata.ClassMetadata; +import org.parchmentmc.feather.metadata.SourceMetadata; +import org.parchmentmc.feather.metadata.SourceMetadataBuilder; +import org.parchmentmc.feather.util.SimpleVersion; + +import java.io.IOException; +import java.util.Iterator; +import java.util.LinkedHashSet; + +public class SourceMetadataDeserializer extends StdDeserializer { + + public SourceMetadataDeserializer() { + super(SourceMetadata.class); + } + + @Override + public SourceMetadata deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ObjectNode node = Jackson.getObjectNode(p); + if (node == null) return null; + + SimpleVersion specVersion = null; + String minecraftVersion = null; + LinkedHashSet classes = null; + + final Iterator propertyNames = node.fieldNames(); + while (propertyNames.hasNext()) { + final String propertyName = propertyNames.next(); + switch (propertyName) { + case "specVersion": + specVersion = ctxt.readTreeAsValue(node.get(propertyName), SimpleVersion.class); // TODO: version checking + break; + case "minecraftVersion": + minecraftVersion = node.get(propertyName).asText(); + break; + case "classes": + classes = ctxt.readTreeAsValue(node.get(propertyName), CommonTypes.SET_CLASS_METADATA); + break; + default: + // do nothing + break; + } + } + + if (specVersion == null) throw new JsonParseException("Specification version is not present"); + if (minecraftVersion == null) throw new JsonParseException("Minecraft version is not present"); + if (classes == null) throw new JsonParseException("Classes Set is not present"); + + return SourceMetadataBuilder.create() + .withMinecraftVersion(minecraftVersion) + .withSpecVersion(specVersion) + .withClasses(classes) + .build(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/SourceMetadataSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/SourceMetadataSerializer.java new file mode 100644 index 0000000..6d5cf25 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/metadata/SourceMetadataSerializer.java @@ -0,0 +1,24 @@ +package org.parchmentmc.feather.io.jackson.modules.metadata; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import org.parchmentmc.feather.metadata.SourceMetadata; + +import java.io.IOException; + +public class SourceMetadataSerializer extends StdSerializer { + + public SourceMetadataSerializer() { + super(SourceMetadata.class); + } + + @Override + public void serialize(SourceMetadata value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeStartObject(); + gen.writePOJOField("specVersion", value.getSpecificationVersion()); + gen.writePOJOField("minecraftVersion", value.getMinecraftVersion()); + gen.writePOJOField("classes", value.getClasses()); + gen.writeEndObject(); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/version/SimpleVersionDeserializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/version/SimpleVersionDeserializer.java new file mode 100644 index 0000000..2a283c4 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/version/SimpleVersionDeserializer.java @@ -0,0 +1,17 @@ +package org.parchmentmc.feather.io.jackson.modules.version; + +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer; +import org.parchmentmc.feather.util.SimpleVersion; + +public class SimpleVersionDeserializer extends FromStringDeserializer { + + public SimpleVersionDeserializer() { + super(SimpleVersion.class); + } + + @Override + protected SimpleVersion _deserialize(String value, DeserializationContext ctxt) { + return SimpleVersion.of(value); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/version/SimpleVersionSerializer.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/version/SimpleVersionSerializer.java new file mode 100644 index 0000000..4747de2 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/modules/version/SimpleVersionSerializer.java @@ -0,0 +1,20 @@ +package org.parchmentmc.feather.io.jackson.modules.version; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer; +import org.parchmentmc.feather.util.SimpleVersion; + +import java.io.IOException; + +public class SimpleVersionSerializer extends StdScalarSerializer { + + public SimpleVersionSerializer() { + super(SimpleVersion.class); + } + + @Override + public void serialize(SimpleVersion value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeString(value.toString()); + } +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/BaseModule.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/BaseModule.java new file mode 100644 index 0000000..d055f17 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/BaseModule.java @@ -0,0 +1,67 @@ +package org.parchmentmc.feather.io.jackson.util; + +import com.fasterxml.jackson.core.Version; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.Module; +import com.fasterxml.jackson.databind.module.SimpleDeserializers; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.module.SimpleSerializers; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Simplified {@link SimpleModule} equivalent, with support for dependencies + */ +public class BaseModule extends Module { + + private final String name; + private final Version version; + private final List dependencies = new ArrayList<>(); + private final SimpleSerializers serializers = new SimpleSerializers(); + private final SimpleDeserializers deserializers = new SimpleDeserializers(); + + public BaseModule(String name, Version version) { + this.name = name; + this.version = version; + } + + @Override + public String getModuleName() { + return name; + } + + @Override + public Version version() { + return version; + } + + protected BaseModule addSerializer(Class type, JsonSerializer serializer) { + this.serializers.addSerializer(type, serializer); + return this; + } + + protected BaseModule addDeserializer(Class type, JsonDeserializer deserializer) { + this.deserializers.addDeserializer(type, deserializer); + return this; + } + + protected BaseModule addDependency(Module module) { + this.dependencies.add(module); + return this; + } + + @Override + public Iterable getDependencies() { + return Collections.unmodifiableCollection(dependencies); + } + + @Override + public void setupModule(SetupContext context) { + context.addSerializers(serializers); + context.addDeserializers(deserializers); + } + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/CommonTypes.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/CommonTypes.java new file mode 100644 index 0000000..34af93c --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/CommonTypes.java @@ -0,0 +1,81 @@ +package org.parchmentmc.feather.io.jackson.util; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; +import org.parchmentmc.feather.mapping.MappingDataContainer; +import org.parchmentmc.feather.metadata.*; +import org.parchmentmc.feather.named.Named; + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; + +public class CommonTypes { + + private CommonTypes() { + throw new IllegalStateException("Can not instantiate an instance of: CommonTypes. This is a utility class"); + } + + private static final TypeFactory TYPE_FACTORY = TypeFactory.defaultInstance(); + + /** + * {@code List} + */ + public static final JavaType LIST_STRING = TYPE_FACTORY.constructCollectionType(List.class, String.class); + + /** + * {@code LinkedHashSet} + */ + public static final JavaType SET_NAMED = TYPE_FACTORY.constructCollectionType(LinkedHashSet.class, Named.class); + + /** + * {@code LinkedHashSet} + */ + public static final JavaType SET_CLASS_METADATA = TYPE_FACTORY.constructCollectionType(LinkedHashSet.class, ClassMetadata.class); + + /** + * {@code LinkedHashSet} + */ + public static final JavaType SET_FIELD_METADATA = TYPE_FACTORY.constructCollectionType(LinkedHashSet.class, FieldMetadata.class); + + /** + * {@code LinkedHashSet} + */ + public static final JavaType SET_METHOD_METADATA = TYPE_FACTORY.constructCollectionType(LinkedHashSet.class, MethodMetadata.class); + + /** + * {@code LinkedHashSet} + */ + public static final JavaType SET_REFERENCE = TYPE_FACTORY.constructCollectionType(LinkedHashSet.class, Reference.class); + + /** + * {@code LinkedHashSet} + */ + public static final JavaType SET_RECORD_METADATA = TYPE_FACTORY.constructCollectionType(LinkedHashSet.class, RecordMetadata.class); + + /** + * {@code Collection} + */ + public static final JavaType COLLECTION_PACKAGE_DATA = TYPE_FACTORY.constructCollectionLikeType(Collection.class, MappingDataContainer.PackageData.class); + + /** + * {@code Collection} + */ + public static final JavaType COLLECTION_CLASS_DATA = TYPE_FACTORY.constructCollectionLikeType(Collection.class, MappingDataContainer.ClassData.class); + + /** + * {@code Collection} + */ + public static final JavaType COLLECTION_FIELD_DATA = TYPE_FACTORY.constructCollectionLikeType(Collection.class, MappingDataContainer.FieldData.class); + + /** + * {@code Collection} + */ + public static final JavaType COLLECTION_METHOD_DATA = TYPE_FACTORY.constructCollectionLikeType(Collection.class, MappingDataContainer.MethodData.class); + + /** + * {@code Collection} + */ + public static final JavaType COLLECTION_PARAMETER_DATA = TYPE_FACTORY.constructCollectionLikeType(Collection.class, MappingDataContainer.ParameterData.class); + +} diff --git a/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/Jackson.java b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/Jackson.java new file mode 100644 index 0000000..9787a10 --- /dev/null +++ b/io-jackson/src/main/java/org/parchmentmc/feather/io/jackson/util/Jackson.java @@ -0,0 +1,35 @@ +package org.parchmentmc.feather.io.jackson.util; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.io.IOException; + +public class Jackson { + + private Jackson() { + throw new IllegalStateException("Can not instantiate an instance of: Jackson. This is a utility class"); + } + + public static > @NonNull P getSerializer(JsonGenerator gen, SerializerProvider provider, Class typeClazz, Class

serializerClass) throws JsonMappingException, JsonGenerationException { + JsonSerializer rawSerializer = provider.findValueSerializer(typeClazz); + if (!serializerClass.isInstance(rawSerializer)) throw new JsonGenerationException("Could not get instance of " + serializerClass.getSimpleName(), gen); + return serializerClass.cast(rawSerializer); + } + + public static @Nullable ObjectNode getObjectNode(JsonParser p) throws IOException { + JsonNode node = p.getCodec().readTree(p); + if (node.isNull()) return null; + if (!node.isObject()) throw new JsonParseException("Expected Object got " + node.getNodeType().name()); + return (ObjectNode) node; + } +} diff --git a/io-jackson/src/test/java/org/parchment/feather/io/jackson/MDCJacksonAdapterFactoryTest.java b/io-jackson/src/test/java/org/parchment/feather/io/jackson/MDCJacksonAdapterFactoryTest.java new file mode 100644 index 0000000..20f7a49 --- /dev/null +++ b/io-jackson/src/test/java/org/parchment/feather/io/jackson/MDCJacksonAdapterFactoryTest.java @@ -0,0 +1,49 @@ +package org.parchment.feather.io.jackson; + +import org.junit.jupiter.api.Test; +import org.parchmentmc.feather.io.jackson.JacksonTest; +import org.parchmentmc.feather.io.jackson.modules.MDCModule; +import org.parchmentmc.feather.manifests.MDCTestConstants; +import org.parchmentmc.feather.mapping.MappingDataContainer.ClassData; +import org.parchmentmc.feather.mapping.MappingDataContainer.FieldData; +import org.parchmentmc.feather.mapping.MappingDataContainer.MethodData; +import org.parchmentmc.feather.mapping.MappingDataContainer.PackageData; +import org.parchmentmc.feather.mapping.VersionedMappingDataContainer; + +import static org.parchmentmc.feather.mapping.ImmutableMappingDataContainer.ParameterData; + +public class MDCJacksonAdapterFactoryTest extends JacksonTest implements MDCTestConstants { + public MDCJacksonAdapterFactoryTest() { + super(b -> b.registerModule(new MDCModule())); + } + + @Test + public void testParameters() { + PARAMETERS.forEach(data -> test(ParameterData.class, data)); + } + + @Test + public void testMethods() { + METHODS.forEach(data -> test(MethodData.class, data)); + } + + @Test + public void testFields() { + FIELDS.forEach(data -> test(FieldData.class, data)); + } + + @Test + public void testClasses() { + CLASSES.forEach(data -> test(ClassData.class, data)); + } + + @Test + public void testPackages() { + PACKAGES.forEach(data -> test(PackageData.class, data)); + } + + @Test + public void testDataContainers() { + DATA_CONTAINERS.forEach(data -> test(VersionedMappingDataContainer.class, data)); + } +} diff --git a/io-jackson/src/test/java/org/parchment/feather/io/jackson/MetadataAdapterFactoryTest.java b/io-jackson/src/test/java/org/parchment/feather/io/jackson/MetadataAdapterFactoryTest.java new file mode 100644 index 0000000..c3551a6 --- /dev/null +++ b/io-jackson/src/test/java/org/parchment/feather/io/jackson/MetadataAdapterFactoryTest.java @@ -0,0 +1,37 @@ +package org.parchment.feather.io.jackson; + +import org.junit.jupiter.api.Test; +import org.parchmentmc.feather.io.jackson.JacksonTest; +import org.parchmentmc.feather.io.jackson.modules.MetadataModule; +import org.parchmentmc.feather.metadata.*; + +public class MetadataAdapterFactoryTest extends JacksonTest implements MetadataTestConstants { + public MetadataAdapterFactoryTest() { + super(b -> b.registerModule(new MetadataModule())); + } + + @Test + public void testMethodReferences() { + METHOD_REFERENCES.forEach(data -> test(Reference.class, data)); + } + + @Test + public void testMethodMetadata() { + METHOD_METADATA.forEach(data -> test(MethodMetadata.class, data)); + } + + @Test + public void testFieldMetadata() { + FIELD_METADATA.forEach(data -> test(FieldMetadata.class, data)); + } + + @Test + public void testClassMetadata() { + CLASS_METADATA.forEach(data -> test(ClassMetadata.class, data)); + } + + @Test + public void testSourceMetadata() { + SOURCE_METADATA.forEach(data -> test(SourceMetadata.class, data)); + } +} diff --git a/io-jackson/src/test/java/org/parchment/feather/io/jackson/OffsetDateTimeAdapterTest.java b/io-jackson/src/test/java/org/parchment/feather/io/jackson/OffsetDateTimeAdapterTest.java new file mode 100644 index 0000000..769b58b --- /dev/null +++ b/io-jackson/src/test/java/org/parchment/feather/io/jackson/OffsetDateTimeAdapterTest.java @@ -0,0 +1,22 @@ +package org.parchment.feather.io.jackson; + +import org.junit.jupiter.api.Test; +import org.parchmentmc.feather.io.jackson.JacksonTest; +import org.parchmentmc.feather.io.jackson.modules.OffsetDateTimeModule; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +public class OffsetDateTimeAdapterTest extends JacksonTest { + public OffsetDateTimeAdapterTest() { + super(b -> b.registerModule(new OffsetDateTimeModule())); + } + + @Test + public void testJackson() { + test(OffsetDateTime.class, OffsetDateTime.MIN); + test(OffsetDateTime.class, OffsetDateTime.MAX); + test(OffsetDateTime.class, OffsetDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC)); + } +} diff --git a/io-jackson/src/test/java/org/parchment/feather/io/jackson/SimpleVersionAdapterTest.java b/io-jackson/src/test/java/org/parchment/feather/io/jackson/SimpleVersionAdapterTest.java new file mode 100644 index 0000000..7585766 --- /dev/null +++ b/io-jackson/src/test/java/org/parchment/feather/io/jackson/SimpleVersionAdapterTest.java @@ -0,0 +1,18 @@ +package org.parchment.feather.io.jackson; + +import org.junit.jupiter.api.Test; +import org.parchmentmc.feather.io.jackson.JacksonTest; +import org.parchmentmc.feather.io.jackson.modules.SimpleVersionModule; +import org.parchmentmc.feather.util.SimpleVersion; + +public class SimpleVersionAdapterTest extends JacksonTest { + public SimpleVersionAdapterTest() { + super(b -> b.registerModule(new SimpleVersionModule())); + } + + @Test + public void testJackson() { + test(SimpleVersion.class, SimpleVersion.of(1, 2, 3)); + test(SimpleVersion.class, SimpleVersion.of("1.4")); + } +} diff --git a/io-jackson/src/testFixtures/java/org/parchmentmc/feather/io/jackson/JacksonTest.java b/io-jackson/src/testFixtures/java/org/parchmentmc/feather/io/jackson/JacksonTest.java new file mode 100644 index 0000000..0baf22c --- /dev/null +++ b/io-jackson/src/testFixtures/java/org/parchmentmc/feather/io/jackson/JacksonTest.java @@ -0,0 +1,67 @@ +package org.parchmentmc.feather.io.jackson; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.function.ThrowingSupplier; + +import java.util.function.Consumer; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Superclass for tests which use Jackson functionality (such as de/serialization tests). + */ +public class JacksonTest { + protected final ObjectMapper jackson; + + protected JacksonTest(Consumer configurator) { + this.jackson = new ObjectMapper(); + configurator.accept(jackson); + } + + /** + * TODO: fixup docs + * Tests the given adapter using the given object. + * + *

This method performs assertions based on the given adapter and object, and asserts that:

+ *
    + *
  1. The adapter {@linkplain Assertions#assertDoesNotThrow(ThrowingSupplier) does not throw an exception} + * while serializing the original object.
  2. + *
  3. The adapter does not throw an exception while deserializing the resulting JSON from assertion #1.
  4. + *
  5. The adapter does not throw an exception while serializing the resulting object from assertion #2.
  6. + *
  7. The adapter does not throw an exception while deserializing the resulting JSON from assertion #3.
  8. + *
  9. The original object and the resulting object from assertion #2 {@linkplain + * Assertions#assertEquals(Object, Object) are equal}.
  10. + *
  11. The resulting objects from assertions #2 and #4 are equal.
  12. + *
  13. The original object and the resulting object from assertion #2 {@linkplain + * Assertions#assertNotSame(Object, Object) are not the same object}.
  14. + *
  15. The resulting objects from assertions #2 and #4 are not the same + * object.
  16. + *
  17. The resulting JSONs from assertions #1 and #4 are equal.
  18. + *
+ * + * @param typeClass The class of the object under test + * @param original The original object + * @param The type of the object under test + */ + protected void test(Class typeClass, T original) { + ObjectWriter writer = jackson.writerFor(typeClass); + + final String originalJson = assertDoesNotThrow(() -> writer.writeValueAsString(original)); + + final T versionA = assertDoesNotThrow(() -> jackson.readValue(originalJson, typeClass)); + + final String versionAJson = assertDoesNotThrow(() -> writer.writeValueAsString(versionA)); + + final T versionB = assertDoesNotThrow(() -> jackson.readValue(versionAJson, typeClass)); + + assertEquals(original, versionA); + assertEquals(versionA, versionB); + + assertNotSame(original, versionA); + assertNotSame(versionA, versionB); + + assertEquals(originalJson, versionAJson); + } +} diff --git a/io-jackson/src/testFixtures/java/org/parchmentmc/feather/io/jackson/spi/JacksonAdapterFactory.java b/io-jackson/src/testFixtures/java/org/parchmentmc/feather/io/jackson/spi/JacksonAdapterFactory.java new file mode 100644 index 0000000..b78cbf0 --- /dev/null +++ b/io-jackson/src/testFixtures/java/org/parchmentmc/feather/io/jackson/spi/JacksonAdapterFactory.java @@ -0,0 +1,49 @@ +package org.parchmentmc.feather.io.jackson.spi; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.parchmentmc.feather.io.jackson.FeatherModule; +import org.parchmentmc.feather.spi.IOAdapter; +import org.parchmentmc.feather.spi.IOAdapterFactory; + +public class JacksonAdapterFactory implements IOAdapterFactory { + + private static final String NAME = "jackson"; + + private static final ObjectMapper jackson = new ObjectMapper().registerModule(new FeatherModule()); + + @Override + public IOAdapter create(Class clazz) { + return new JacksonWrapper<>(clazz); + } + + @Override + public String name() { + return NAME; + } + + static class JacksonWrapper implements IOAdapter { + + private final Class typeClass; + + JacksonWrapper(Class typeClass) { + this.typeClass = typeClass; + } + + @Override + public String name() { + return NAME; + } + + @Override + public T fromJson(String input) throws JsonProcessingException { + return jackson.readValue(input, typeClass); + } + + @Override + public String toJson(T value) throws JsonProcessingException { + return jackson.writeValueAsString(value); + } + } + +} diff --git a/io-jackson/src/testFixtures/resources/META-INF/services/org.parchmentmc.feather.spi.IOAdapterFactory b/io-jackson/src/testFixtures/resources/META-INF/services/org.parchmentmc.feather.spi.IOAdapterFactory new file mode 100644 index 0000000..aaa37d2 --- /dev/null +++ b/io-jackson/src/testFixtures/resources/META-INF/services/org.parchmentmc.feather.spi.IOAdapterFactory @@ -0,0 +1 @@ +org.parchmentmc.feather.io.jackson.spi.JacksonAdapterFactory \ No newline at end of file diff --git a/io-tests/build.gradle b/io-tests/build.gradle index a126b13..ec1f8e0 100644 --- a/io-tests/build.gradle +++ b/io-tests/build.gradle @@ -10,4 +10,7 @@ dependencies { implementation project(':io-moshi') testImplementation testFixtures(project(':io-moshi')) + + implementation project(':io-jackson') + testImplementation testFixtures(project(':io-jackson')) } diff --git a/io-tests/src/test/java/org/parchmentmc/feather/io/tests/AdapterPresenceTest.java b/io-tests/src/test/java/org/parchmentmc/feather/io/tests/AdapterPresenceTest.java index d7fa320..0af57e5 100644 --- a/io-tests/src/test/java/org/parchmentmc/feather/io/tests/AdapterPresenceTest.java +++ b/io-tests/src/test/java/org/parchmentmc/feather/io/tests/AdapterPresenceTest.java @@ -11,7 +11,7 @@ public class AdapterPresenceTest { private static final ServiceLoader CONVERTERS = ServiceLoader.load(IOAdapterFactory.class); - private static final String[] EXPECTED_ADAPTERS = new String[] { "gson", "moshi" }; + private static final String[] EXPECTED_ADAPTERS = new String[] { "gson", "moshi", "jackson" }; @Test public void insureExpectedAdaptersAreActuallyPresent() { diff --git a/settings.gradle b/settings.gradle index 2d379d3..e29a888 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,6 +17,8 @@ include 'core' project(':core').name = 'feather' include 'io-moshi' project(':io-moshi').name = 'io-moshi' +include 'io-jackson' +project(':io-jackson').name = 'io-jackson' include 'io-gson' project(':io-gson').name = 'io-gson' include 'io-proguard'