diff --git a/pom.xml b/pom.xml index a624d701..6ac593c4 100644 --- a/pom.xml +++ b/pom.xml @@ -87,7 +87,7 @@ UTF-8 [17,18) 8 - 9.15.1 + 0.0.0.translate-syntax-3-SNAPSHOT configured-by-release-profile @@ -336,10 +336,10 @@ com.fasterxml.jackson.module jackson-module-parameter-names - - com.fasterxml.jackson.module - jackson-module-blackbird - + + + + com.fasterxml.jackson.datatype jackson-datatype-jdk8 diff --git a/src/main/java/com/regnosys/rosetta/common/hashing/GlobalKeyProcessStep.java b/src/main/java/com/regnosys/rosetta/common/hashing/GlobalKeyProcessStep.java index fa8e161c..f6406dca 100644 --- a/src/main/java/com/regnosys/rosetta/common/hashing/GlobalKeyProcessStep.java +++ b/src/main/java/com/regnosys/rosetta/common/hashing/GlobalKeyProcessStep.java @@ -65,7 +65,7 @@ public KeyPostProcessReport runProcessStep(Class< RosettaModelObjectBuilder builder = instance.toBuilder(); KeyPostProcessReport thisReport = new KeyPostProcessReport(builder, new HashMap<>()); ReKeyProcessor reKeyProcessor = new ReKeyProcessor(thisReport); - RosettaPath path = RosettaPath.valueOf(topClass.getSimpleName()); + RosettaPath path = RosettaPath.valueOf(instance.getType().getSimpleName()); reKeyProcessor.processRosetta(path, topClass, builder, null); builder.process(path, reKeyProcessor); return thisReport; diff --git a/src/main/java/com/regnosys/rosetta/common/hashing/ReKeyProcessStep.java b/src/main/java/com/regnosys/rosetta/common/hashing/ReKeyProcessStep.java index 0ef46ce5..4e648c18 100644 --- a/src/main/java/com/regnosys/rosetta/common/hashing/ReKeyProcessStep.java +++ b/src/main/java/com/regnosys/rosetta/common/hashing/ReKeyProcessStep.java @@ -48,7 +48,7 @@ public ReKeyProcessStep(GlobalKeyProcessStep keyProcessor) { @Override public PostProcessorReport runProcessStep(Class topClass, T instance) { - RosettaPath path = RosettaPath.valueOf(topClass.getSimpleName()); + RosettaPath path = RosettaPath.valueOf(instance.getType().getSimpleName()); RosettaModelObjectBuilder builder = instance.toBuilder(); ReKeyPostProcessReport report = new ReKeyPostProcessReport(builder); ReKeyProcessor processor = new ReKeyProcessor(report, keyProcessor.runProcessStep(topClass, instance)); diff --git a/src/main/java/com/regnosys/rosetta/common/hashing/ReferenceResolverProcessStep.java b/src/main/java/com/regnosys/rosetta/common/hashing/ReferenceResolverProcessStep.java index 17f93001..b35af1ad 100644 --- a/src/main/java/com/regnosys/rosetta/common/hashing/ReferenceResolverProcessStep.java +++ b/src/main/java/com/regnosys/rosetta/common/hashing/ReferenceResolverProcessStep.java @@ -70,7 +70,7 @@ public String getName() { public ReferenceResolverPostProcessorReport runProcessStep( Class topClass, T instance) { - RosettaPath path = RosettaPath.valueOf(topClass.getSimpleName()); + RosettaPath path = RosettaPath.valueOf(instance.getType().getSimpleName()); ReferenceCollector collector = new ReferenceCollector(referenceConfig); instance.process(path, collector); ReferenceResolver resolver = diff --git a/src/main/java/com/regnosys/rosetta/common/merging/MergeTemplateProcessStep.java b/src/main/java/com/regnosys/rosetta/common/merging/MergeTemplateProcessStep.java index 6ef946c5..fcaa5b85 100644 --- a/src/main/java/com/regnosys/rosetta/common/merging/MergeTemplateProcessStep.java +++ b/src/main/java/com/regnosys/rosetta/common/merging/MergeTemplateProcessStep.java @@ -64,7 +64,7 @@ public String getName() { @Override public PostProcessorReport runProcessStep(Class topClass, T instance) { MergeTemplateBuilderProcessor process = new MergeTemplateBuilderProcessor(); - RosettaPath path = RosettaPath.valueOf(topClass.getSimpleName()); + RosettaPath path = RosettaPath.valueOf(instance.getType().getSimpleName()); RosettaModelObjectBuilder builder= instance.toBuilder(); process.processRosetta(path, topClass, builder, null); builder.process(path, process); diff --git a/src/main/java/com/regnosys/rosetta/common/postprocess/qualify/QualifyProcessorStep.java b/src/main/java/com/regnosys/rosetta/common/postprocess/qualify/QualifyProcessorStep.java index bffc929f..5c94c006 100644 --- a/src/main/java/com/regnosys/rosetta/common/postprocess/qualify/QualifyProcessorStep.java +++ b/src/main/java/com/regnosys/rosetta/common/postprocess/qualify/QualifyProcessorStep.java @@ -54,7 +54,7 @@ public String getName() { @Override public QualificationReport runProcessStep(Class topClass, T instance) { - RosettaPath path = RosettaPath.valueOf(topClass.getSimpleName()); + RosettaPath path = RosettaPath.valueOf(instance.getType().getSimpleName()); RosettaModelObjectBuilder builder = (RosettaModelObjectBuilder) instance; List collectedResults = new ArrayList<>(); diff --git a/src/main/java/com/regnosys/rosetta/common/serialisation/RosettaObjectMapper.java b/src/main/java/com/regnosys/rosetta/common/serialisation/RosettaObjectMapper.java index 3c1ebaf3..7cc64767 100644 --- a/src/main/java/com/regnosys/rosetta/common/serialisation/RosettaObjectMapper.java +++ b/src/main/java/com/regnosys/rosetta/common/serialisation/RosettaObjectMapper.java @@ -21,7 +21,7 @@ */ import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.module.blackbird.BlackbirdModule; +//import com.fasterxml.jackson.module.blackbird.BlackbirdModule; /** * Returns a pre-configured {@link ObjectMapper} that serves as the default when @@ -42,7 +42,7 @@ public static ObjectMapper getNewMinimalRosettaObjectMapper() { * Creating new RosettaObjectMapper instances is expensive, use the singleton instance if possible. */ public static ObjectMapper getNewRosettaObjectMapper() { - return getNewMinimalRosettaObjectMapper() - .registerModule(new BlackbirdModule()); + return getNewMinimalRosettaObjectMapper(); + // .registerModule(new BlackbirdModule()); } } diff --git a/src/main/java/com/regnosys/rosetta/common/serialisation/mixin/RosettaJSONAnnotationIntrospector.java b/src/main/java/com/regnosys/rosetta/common/serialisation/mixin/RosettaJSONAnnotationIntrospector.java index 27d39a1f..dfc4fb0d 100644 --- a/src/main/java/com/regnosys/rosetta/common/serialisation/mixin/RosettaJSONAnnotationIntrospector.java +++ b/src/main/java/com/regnosys/rosetta/common/serialisation/mixin/RosettaJSONAnnotationIntrospector.java @@ -21,15 +21,19 @@ */ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonUnwrapped; import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.databind.PropertyName; import com.fasterxml.jackson.databind.cfg.MapperConfig; import com.fasterxml.jackson.databind.introspect.*; +import com.fasterxml.jackson.databind.util.NameTransformer; import com.regnosys.rosetta.common.serialisation.BackwardsCompatibleAnnotationIntrospector; import com.regnosys.rosetta.common.serialisation.BeanUtil; import com.regnosys.rosetta.common.serialisation.mixin.legacy.LegacyRosettaBuilderIntrospector; import com.rosetta.model.lib.annotations.RosettaAttribute; import com.rosetta.model.lib.annotations.RosettaDataType; +import com.rosetta.model.lib.meta.RosettaOriginalProxy; +import com.rosetta.model.lib.meta.RosettaProxy; import java.util.*; import java.util.function.Predicate; @@ -68,6 +72,11 @@ public Class findPOJOBuilder(AnnotatedClass ac) { public PropertyName findNameForSerialization(Annotated a) { if (a.hasAnnotation(RosettaAttribute.class)) { return new PropertyName(a.getAnnotation(RosettaAttribute.class).value()); + } else if (a instanceof AnnotatedMethod) { + AnnotatedMethod m = (AnnotatedMethod) a; + if (RosettaProxy.class.isAssignableFrom(m.getDeclaringClass()) && m.getName().equals("getKey")) { + return new PropertyName("@referenceKey"); + } } return super.findNameForSerialization(a); } @@ -107,11 +116,30 @@ public JsonIgnoreProperties.Value findPropertyIgnoralByName(MapperConfig conf return findPropertyIgnorals(ann); } + @Override + public NameTransformer findUnwrappingNameTransformer(AnnotatedMember member) + { + if (RosettaProxy.class.isAssignableFrom(member.getDeclaringClass()) && member.getName().equals("getInstance")) { + return NameTransformer.simpleTransformer("", ""); + } + return super.findUnwrappingNameTransformer(member); + } + @Deprecated @Override public JsonIgnoreProperties.Value findPropertyIgnorals(Annotated ac) { if (ac instanceof AnnotatedClass && ac.hasAnnotation(RosettaDataType.class)) { AnnotatedClass acc = (AnnotatedClass) ac; + if (RosettaProxy.class.isAssignableFrom(ac.getRawType())) { + Set includedNames = new HashSet<>(); + if (RosettaOriginalProxy.class.isAssignableFrom(ac.getRawType())) { + includedNames.add("getInstance"); + } else { + includedNames.add("getKey"); + } + Set ignored = getPropertyNames(acc, x -> !includedNames.contains(x.getName())); + return JsonIgnoreProperties.Value.forIgnoredProperties(ignored).withAllowSetters(); + } Set includes = getPropertyNames(acc, x -> x.hasAnnotation(RosettaAttribute.class)); Set ignored = getPropertyNames(acc, x -> !x.hasAnnotation(RosettaAttribute.class)); ignored.removeAll(includes); @@ -125,7 +153,7 @@ public JsonIgnoreProperties.Value findPropertyIgnorals(Annotated ac) { private static Set getPropertyNames(AnnotatedClass acc, Predicate filter) { return StreamSupport.stream(acc.memberMethods().spliterator(), false) .filter(filter) - .map(m -> BeanUtil.getPropertyName(m.getAnnotated())) + .map(m -> m.getName().equals("getKey") ? "@referenceKey" : BeanUtil.getPropertyName(m.getAnnotated())) .filter(Objects::nonNull) .collect(Collectors.toSet()); } diff --git a/src/main/java/com/regnosys/rosetta/common/translation/MappingProcessorStep.java b/src/main/java/com/regnosys/rosetta/common/translation/MappingProcessorStep.java index 8992dfbf..b4a502b0 100644 --- a/src/main/java/com/regnosys/rosetta/common/translation/MappingProcessorStep.java +++ b/src/main/java/com/regnosys/rosetta/common/translation/MappingProcessorStep.java @@ -80,7 +80,7 @@ public PostProcessorReport runProcessStep(Class mappingsFuture = executor.submit(() -> { - RosettaPath path = RosettaPath.valueOf(topClass.getSimpleName()); + RosettaPath path = RosettaPath.valueOf(instance.getType().getSimpleName()); for (MappingDelegate mapper : mappingDelegates) { LOGGER.debug("Running mapper {} for model path {}", mapper.getClass().getSimpleName(), mapper.getModelPath()); MappingBuilderProcessor processor = new MappingBuilderProcessor(mapper); diff --git a/src/main/java/com/regnosys/rosetta/common/util/RosettaObjectCollectorProcessStep.java b/src/main/java/com/regnosys/rosetta/common/util/RosettaObjectCollectorProcessStep.java index 6a90dcd5..3e549c0d 100644 --- a/src/main/java/com/regnosys/rosetta/common/util/RosettaObjectCollectorProcessStep.java +++ b/src/main/java/com/regnosys/rosetta/common/util/RosettaObjectCollectorProcessStep.java @@ -52,7 +52,7 @@ public String getName() { public RosettaObjectCollectorProcessReport runProcessStep(Class topClass, T instance) { List collectedObjects = new ArrayList<>(); RosettaObjectCollectorProcess process = new RosettaObjectCollectorProcess<>(collectRosettaType, collectedObjects); - RosettaPath path = RosettaPath.valueOf(topClass.getSimpleName()); + RosettaPath path = RosettaPath.valueOf(instance.getType().getSimpleName()); process.processRosetta(path, topClass, instance, null); instance.process(path, process); return new RosettaObjectCollectorProcessReport<>(instance, collectedObjects); diff --git a/src/main/java/com/regnosys/rosetta/common/validation/RosettaTypeValidator.java b/src/main/java/com/regnosys/rosetta/common/validation/RosettaTypeValidator.java index 0f24f7e4..c3b2ec53 100644 --- a/src/main/java/com/regnosys/rosetta/common/validation/RosettaTypeValidator.java +++ b/src/main/java/com/regnosys/rosetta/common/validation/RosettaTypeValidator.java @@ -49,10 +49,10 @@ public class RosettaTypeValidator implements PostProcessStep { @Override public ValidationReport runProcessStep(Class topClass, T instance) { - LOGGER.debug("Running validation for " + topClass.getSimpleName()); + LOGGER.debug("Running validation for " + instance.getType().getSimpleName()); ValidationReport report = new ValidationReport(instance, new ArrayList<>()); RosettaTypeProcessor processor = new RosettaTypeProcessor(report); - RosettaPath path = RosettaPath.valueOf(topClass.getSimpleName()); + RosettaPath path = RosettaPath.valueOf(instance.getType().getSimpleName()); processor.processRosetta(path, topClass, instance, null); instance.process(path, processor); return report; diff --git a/src/test/java/com/regnosys/rosetta/common/serialisation/json/ProxySerialisationTest.java b/src/test/java/com/regnosys/rosetta/common/serialisation/json/ProxySerialisationTest.java new file mode 100644 index 00000000..413860b7 --- /dev/null +++ b/src/test/java/com/regnosys/rosetta/common/serialisation/json/ProxySerialisationTest.java @@ -0,0 +1,86 @@ +package com.regnosys.rosetta.common.serialisation.json; + +/*- + * ============== + * Rune Common + * ============== + * Copyright (C) 2018 - 2024 REGnosys + * ============== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============== + */ + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.regnosys.rosetta.common.serialisation.RosettaObjectMapper; +import com.regnosys.rosetta.tests.RosettaInjectorProvider; +import com.regnosys.rosetta.tests.util.CodeGeneratorTestHelper; +import com.rosetta.model.lib.RosettaModelObject; +import com.rosetta.model.lib.RosettaModelObjectBuilder; +import com.rosetta.model.lib.annotations.RosettaDataType; +import com.rosetta.model.lib.meta.ReferenceService; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import javax.inject.Inject; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@ExtendWith(InjectionExtension.class) +@InjectWith(RosettaInjectorProvider.class) +public class ProxySerialisationTest { + + @Inject + CodeGeneratorTestHelper codeGeneratorTestHelper; + @Inject + ReferenceService referenceService; + + @Test + void testProxySerialisation() throws JsonProcessingException { + ObjectMapper mapper = RosettaObjectMapper.getNewRosettaObjectMapper(); + + String rosetta = "type A:\n" + + " attr1 string (0..1)\n" + + " attr2 string (0..1)\n"; + + String expectedJson = "{\"@referenceKey\":\"key\"}"; + String expectedOriginalJson = "{\"attr1\":\"foo\",\"attr2\":\"bar\"}"; + + HashMap generatedCode = codeGeneratorTestHelper.generateCode(rosetta); + Map> compiledCode = codeGeneratorTestHelper.compileToClasses(generatedCode); + + Class compiledClass = (Class)compiledCode.get("com.rosetta.test.model.A"); + + RosettaModelObject value = mapper.readValue(expectedOriginalJson, compiledClass); + RosettaModelObject originalInstance = referenceService.register(value, "key", compiledClass); + RosettaModelObject proxy = referenceService.getProxy("key", compiledClass); + + String actualJson = mapper.writeValueAsString(proxy); + assertJsonEquals(expectedJson, actualJson); + + String actualOriginalJson = mapper.writeValueAsString(originalInstance); + assertJsonEquals(expectedOriginalJson, actualOriginalJson); + } + + private void assertJsonEquals(String expectedJson, String actualJson) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TreeMap expectedJsonMap = mapper.readValue(expectedJson, TreeMap.class); + TreeMap actualJsonMap = mapper.readValue(actualJson, TreeMap.class); + assertEquals(expectedJsonMap, actualJsonMap); + } +} diff --git a/src/test/java/com/regnosys/rosetta/common/translation/MappingProcessorStepTest.java b/src/test/java/com/regnosys/rosetta/common/translation/MappingProcessorStepTest.java index 427bee86..cbcbe63c 100644 --- a/src/test/java/com/regnosys/rosetta/common/translation/MappingProcessorStepTest.java +++ b/src/test/java/com/regnosys/rosetta/common/translation/MappingProcessorStepTest.java @@ -252,7 +252,7 @@ public RosettaModelObjectBuilder toBuilder() { @Override public Class getType() { - throw new UnsupportedOperationException("method getType in RosettaModelObject has not been implemented"); + return TestModel.class; } @Override