Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
class DspCatalogRequestActionTest {

private final ProtocolRemoteMessageDispatcher messageDispatcher = mock();
private final TypeTransformerRegistry typeTransformerRegistry = new TypeTransformerRegistryImpl();
private final TypeTransformerRegistry typeTransformerRegistry = new TypeTransformerRegistryImpl(mock());
private final ObjectMapper objectMapper = createObjectMapper();
private final SingleParticipantContextSupplier participantContextSupplier = () -> ServiceResult.success(
ParticipantContext.Builder.newInstance().participantContextId("participantContext").identity("identity").build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class PagingCatalogFetcherTest {
private final ObjectMapper objectMapper = createObjectMapper();
private final SingleParticipantContextSupplier participantContextSupplier = () -> ServiceResult.success(
ParticipantContext.Builder.newInstance().participantContextId("participantContext").identity("identity").build());
private final TypeTransformerRegistry typeTransformerRegistry = new TypeTransformerRegistryImpl();
private final TypeTransformerRegistry typeTransformerRegistry = new TypeTransformerRegistryImpl(mock());
private PagingCatalogFetcher fetcher;

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class ManagementApiSchemaTest {

private final ObjectMapper objectMapper = JacksonJsonLd.createObjectMapper();
private final TypeManager typeManager = mock();
private final TypeTransformerRegistry transformer = new TypeTransformerRegistryImpl();
private final TypeTransformerRegistry transformer = new TypeTransformerRegistryImpl(mock());

@BeforeEach
void setUp() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ApiCoreSchemaTest {

private final ObjectMapper objectMapper = JacksonJsonLd.createObjectMapper();
private final TypeManager typeManager = mock();
private final TypeTransformerRegistry transformer = new TypeTransformerRegistryImpl();
private final TypeTransformerRegistry transformer = new TypeTransformerRegistryImpl(mock());
private final CriterionOperatorRegistry criterionOperatorRegistry = CriterionOperatorRegistryImpl.ofDefaults();

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,53 +15,78 @@
package org.eclipse.edc.transform;

import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.spi.result.Result;
import org.eclipse.edc.transform.spi.TypeTransformer;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BinaryOperator;

import static java.lang.String.format;

public class TypeTransformerRegistryImpl implements TypeTransformerRegistry {
private final Map<String, Class<?>> aliases = new HashMap<>();
private final List<TypeTransformer<?, ?>> transformers = new ArrayList<>();

private final Map<Class<?>, Map<Class<?>, TypeTransformer<?, ?>>> transformers = new HashMap<>();
private final Map<String, TypeTransformerRegistry> contextRegistries = new HashMap<>();
private final Monitor monitor;
private TypeTransformerRegistry parent;

public TypeTransformerRegistryImpl() {
public TypeTransformerRegistryImpl(Monitor monitor) {
this.monitor = monitor;
}

private TypeTransformerRegistryImpl(TypeTransformerRegistry parent) {
private TypeTransformerRegistryImpl(TypeTransformerRegistryImpl parent) {
this.parent = parent;
this.monitor = parent.monitor;
}

@Override
public void register(TypeTransformer<?, ?> transformer) {
this.transformers.add(transformer);
var overriddenTransformer = transformers.computeIfAbsent(transformer.getInputType(), key -> new HashMap<>())
.put(transformer.getOutputType(), transformer);
if (overriddenTransformer != null) {
monitor.warning(format("Overriding transformer registered for %s -> %s", transformer.getInputType(), transformer.getOutputType()));
}
}

@Override
public @NotNull TypeTransformerRegistry forContext(String context) {
return contextRegistries.computeIfAbsent(context, k -> new TypeTransformerRegistryImpl(this));
}

@SuppressWarnings("unchecked")
@Override
public @NotNull <INPUT, OUTPUT> TypeTransformer<INPUT, OUTPUT> transformerFor(@NotNull INPUT input, @NotNull Class<OUTPUT> outputType) {
return transformers.stream()
.filter(t -> t.getInputType().isInstance(input) && t.getOutputType().equals(outputType))
.findAny()
.map(it -> (TypeTransformer<INPUT, OUTPUT>) it)
return transformers.entrySet().stream()
.filter(entry -> entry.getKey().isInstance(input))
.filter(entry -> entry.getValue().containsKey(outputType))
.<Class<?>>map(Map.Entry::getKey)
.reduce(selectMostSpecificType(input.getClass(), outputType))
.map(transformers::get)
.map(it -> (TypeTransformer<INPUT, OUTPUT>) it.get(outputType))
.or(() -> Optional.ofNullable(parent).map(p -> p.transformerFor(input, outputType)))
.orElseThrow(() -> new EdcException(format("No Transformer registered that can handle %s -> %s", input.getClass(), outputType)));
}

private BinaryOperator<Class<?>> selectMostSpecificType(Class<?> inputType, Class<?> outputType) {
return (current, candidate) -> {
if (candidate.isAssignableFrom(current)) {
return current;
}

if (current.isAssignableFrom(candidate)) {
return candidate;
}

throw new EdcException(format("Ambiguous transformers registered for %s -> %s", inputType, outputType));
};
}

@Override
public <INPUT, OUTPUT> Result<OUTPUT> transform(@NotNull INPUT input, @NotNull Class<OUTPUT> outputType) {
Objects.requireNonNull(input);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2026 Amadeus
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Amadeus - Initial API and Implementation
*
*/

package org.eclipse.edc.transform;

import org.eclipse.edc.transform.spi.TransformerContext;
import org.eclipse.edc.transform.spi.TypeTransformer;

public class TestTypeTransformer<INPUT, OUTPUT> implements TypeTransformer<INPUT, OUTPUT> {
private final Class<INPUT> inputType;
private final Class<OUTPUT> outputType;

public TestTypeTransformer(Class<INPUT> inputType, Class<OUTPUT> outputType) {
this.inputType = inputType;
this.outputType = outputType;
}

@Override
public Class<INPUT> getInputType() {
return inputType;
}

@Override
public Class<OUTPUT> getOutputType() {
return outputType;
}

@Override
public OUTPUT transform(INPUT input, TransformerContext context) {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.eclipse.edc.transform;

import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.transform.spi.TypeTransformer;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -24,12 +25,16 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;

public class TypeTransformerRegistryImplTest {

private final TypeTransformerRegistry registry = new TypeTransformerRegistryImpl();
private final Monitor monitor = mock();
private final TypeTransformerRegistry registry = new TypeTransformerRegistryImpl(monitor);

@BeforeEach
void setUp() {
Expand All @@ -46,6 +51,35 @@ void shouldReturnTheCorrectTransformer() {
assertThat(transformer).isInstanceOf(StringIntegerTypeTransformer.class);
}

@Test
void shouldReplaceTransformerForTheSameInputAndOutputTypes() {
var replacement = new TestTypeTransformer<>(String.class, Integer.class);
registry.register(replacement);

assertThat(registry.transformerFor("a string", Integer.class)).isSameAs(replacement);
verify(monitor).warning(contains("Overriding transformer registered"));
}

@Test
void shouldReturnMostSpecificCompatibleTransformer() {
var objectTransformer = new TestTypeTransformer<>(Object.class, Long.class);
var charSequenceTransformer = new TestTypeTransformer<>(CharSequence.class, Long.class);
registry.register(objectTransformer);
registry.register(charSequenceTransformer);

assertThat(registry.transformerFor("a string", Long.class)).isSameAs(charSequenceTransformer);
}

@Test
void shouldThrowExceptionWhenCompatibleTransformersAreAmbiguous() {
registry.register(new TestTypeTransformer<>(CharSequence.class, Long.class));
registry.register(new TestTypeTransformer<>(Comparable.class, Long.class));

assertThatThrownBy(() -> registry.transformerFor("a string", Long.class))
.isInstanceOf(EdcException.class)
.hasMessageContaining("Ambiguous transformers");
}

@Test
void shouldThrowExceptionWhenTransformerDoesNotExist() {
var notString = 4L;
Expand Down Expand Up @@ -96,13 +130,23 @@ void shouldTransformUsingNestedContext() {
TypeTransformer<Integer, String> typeTransformer = mock();
contextRegistry.register(typeTransformer);
registry.register(typeTransformer);
clearInvocations((Object) typeTransformer);

assertThat(nestedContextRegistry.transform(5, String.class))
.isSucceeded().isEqualTo("5");

verifyNoInteractions(typeTransformer);
}

@Test
void shouldOverrideParentTransformer() {
var replacement = new TestTypeTransformer<>(String.class, Integer.class);
contextRegistry.register(replacement);

assertThat(contextRegistry.transformerFor("a string", Integer.class)).isSameAs(replacement);
assertThat(registry.transformerFor("a string", Integer.class)).isInstanceOf(StringIntegerTypeTransformer.class);
}

}

@Nested
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ public EventRouter eventRouter(ServiceExtensionContext context) {
}

@Provider
public TypeTransformerRegistry typeTransformerRegistry() {
return new TypeTransformerRegistryImpl();
public TypeTransformerRegistry typeTransformerRegistry(ServiceExtensionContext context) {
return new TypeTransformerRegistryImpl(context.getMonitor());
}

@Provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class JsonObjectToParticipantContextTransformerTest {
@BeforeEach
void setUp() {
var transformer = new JsonObjectToParticipantContextTransformer();
typeTransformerRegistry = new TypeTransformerRegistryImpl();
typeTransformerRegistry = new TypeTransformerRegistryImpl(mock());
typeTransformerRegistry.register(new JsonValueToGenericTypeTransformer(typeManager, "test"));
typeTransformerRegistry.register(transformer);
typeTransformerRegistry.register(new JsonObjectToDataAddressTransformer());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class JsonObjectToAssetTransformerTest {
@BeforeEach
void setUp() {
var transformer = new JsonObjectToAssetTransformer();
typeTransformerRegistry = new TypeTransformerRegistryImpl();
typeTransformerRegistry = new TypeTransformerRegistryImpl(mock());
typeTransformerRegistry.register(new JsonValueToGenericTypeTransformer(typeManager, "test"));
typeTransformerRegistry.register(transformer);
typeTransformerRegistry.register(new JsonObjectToDataAddressTransformer());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class JsonObjectToDataplaneMetadataTransformerTest {
@BeforeEach
void setUp() {
var transformer = new JsonObjectToDataplaneMetadataTransformer();
typeTransformerRegistry = new TypeTransformerRegistryImpl();
typeTransformerRegistry = new TypeTransformerRegistryImpl(mock());
typeTransformerRegistry.register(new JsonValueToGenericTypeTransformer(typeManager, "test"));
typeTransformerRegistry.register(transformer);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
class Base64ContinuationTokenSerDesTest {

private final TypeManager typeManager = mock();
private final TypeTransformerRegistryImpl typeTransformerRegistry = new TypeTransformerRegistryImpl();
private final TypeTransformerRegistryImpl typeTransformerRegistry = new TypeTransformerRegistryImpl(mock());
private final ObjectMapper objectMapper = JacksonJsonLd.createObjectMapper();
private final Base64continuationTokenSerDes serDes = new Base64continuationTokenSerDes(typeTransformerRegistry, new TitaniumJsonLd(mock()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;
import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_CONNECTOR_MANAGEMENT_CONTEXT_V2;
import static org.mockito.Mockito.mock;

class JsonObjectToCachedDocumentTransformerTest {

Expand All @@ -41,7 +42,7 @@ class JsonObjectToCachedDocumentTransformerTest {

@BeforeEach
void setUp() {
registry = new TypeTransformerRegistryImpl();
registry = new TypeTransformerRegistryImpl(mock());
registry.register(new JsonObjectToCachedDocumentTransformer());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat;
import static org.mockito.Mockito.mock;

class JsonObjectFromSchemaValidatorRegistrationTransformerTest {

Expand All @@ -36,7 +37,7 @@ class JsonObjectFromSchemaValidatorRegistrationTransformerTest {

@BeforeEach
void setUp() {
registry = new TypeTransformerRegistryImpl();
registry = new TypeTransformerRegistryImpl(mock());
registry.register(new JsonObjectFromSchemaValidatorRegistrationTransformer(jsonFactory));
registry.register(new JsonObjectToSchemaValidatorRegistrationTransformer());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_CONNECTOR_MANAGEMENT_CONTEXT_V2;
import static org.eclipse.edc.validator.registration.spi.SchemaValidatorRegistration.SCHEMA_VALIDATOR_REGISTRATION_TYPE_TERM;
import static org.mockito.Mockito.mock;

class JsonObjectToSchemaValidatorRegistrationTransformerTest {

Expand All @@ -40,7 +41,7 @@ class JsonObjectToSchemaValidatorRegistrationTransformerTest {

@BeforeEach
void setUp() {
registry = new TypeTransformerRegistryImpl();
registry = new TypeTransformerRegistryImpl(mock());
registry.register(new JsonObjectToSchemaValidatorRegistrationTransformer());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class PresentationResponseMessageSerdeTest {

private final ObjectMapper mapper = JacksonJsonLd.createObjectMapper();
private final TypeManager typeManager = mock();
private final TypeTransformerRegistry trr = new TypeTransformerRegistryImpl();
private final TypeTransformerRegistry trr = new TypeTransformerRegistryImpl(mock());
private final TransformerContext context = new TransformerContextImpl(trr);


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
class JsonObjectToPresentationQueryMessageTransformerTest {
private final ObjectMapper mapper = JacksonJsonLd.createObjectMapper();
private final TypeManager typeManager = mock();
private final TypeTransformerRegistry trr = new TypeTransformerRegistryImpl();
private final TypeTransformerRegistry trr = new TypeTransformerRegistryImpl(mock());
private final TransformerContext context = new TransformerContextImpl(trr);


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
class JsonObjectToPresentationResponseMessageTransformerTest {
private final ObjectMapper mapper = JacksonJsonLd.createObjectMapper();
private final TypeManager typeManager = mock();
private final TypeTransformerRegistry trr = new TypeTransformerRegistryImpl();
private final TypeTransformerRegistry trr = new TypeTransformerRegistryImpl(mock());
private final TransformerContext context = new TransformerContextImpl(trr);

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class JsonObjectToVerifiableCredentialTransformerTest {
@BeforeEach
void setUp() {
transformer = new JsonObjectToVerifiableCredentialTransformer();
var registry = new TypeTransformerRegistryImpl();
var registry = new TypeTransformerRegistryImpl(mock());
registry.register(new JsonObjectToCredentialSubjectTransformer());
registry.register(new JsonObjectToCredentialStatusTransformer());
registry.register(new JsonValueToGenericTypeTransformer(typeManager, "test"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class JsonObjectToVerifiablePresentationTransformerTest {
@BeforeEach
void setup() {
transformer = new JsonObjectToVerifiablePresentationTransformer();
var registry = new TypeTransformerRegistryImpl();
var registry = new TypeTransformerRegistryImpl(mock());
registry.register(new JsonObjectToCredentialSubjectTransformer());
registry.register(new JsonObjectToCredentialStatusTransformer());
registry.register(new JsonObjectToVerifiableCredentialTransformer());
Expand Down
Loading
Loading