Skip to content

refactor: change TypeTransformerRegistry to use a Map instead of Arraylist - #5929

Open
mokhairymahmoud wants to merge 3 commits into
eclipse-edc:mainfrom
mokhairymahmoud:feat/transformerRegistry
Open

refactor: change TypeTransformerRegistry to use a Map instead of Arraylist#5929
mokhairymahmoud wants to merge 3 commits into
eclipse-edc:mainfrom
mokhairymahmoud:feat/transformerRegistry

Conversation

@mokhairymahmoud

Copy link
Copy Markdown
Contributor

What this PR changes/adds

This PR is to change the current TypeTransformerRegistry from an ArrayList to be a Map. This guarantees the existence of only one unique transformer type in the registry and make the transformer selection more deterministic. The PR is the implementation of this DR

Why it does that

The current way of tackling the typeTransformerRegistry is based on ArrayList with a selection mechanism based on findAny() which makes it indeterministic to select a specific transformer specially if there are two of the same type.

Linked Issue(s)

Related to #5921

Please be sure to take a look at the contributing guidelines and our etiquette for pull requests.

@mokhairymahmoud
mokhairymahmoud requested a review from a team as a code owner July 29, 2026 13:56
@mokhairymahmoud mokhairymahmoud added core feature refactoring Cleaning up code and dependencies and removed core feature labels Jul 29, 2026
@mokhairymahmoud mokhairymahmoud changed the title feat: change TypeTransformerRegistry to use a Map instead of Arraylist refactor: change TypeTransformerRegistry to use a Map instead of Arraylist Jul 29, 2026
@@ -31,7 +29,7 @@

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's been a while that I see this aliases unused field, since you're here, could you please delete it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2022 - 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: copyright

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed it

@Override
public void register(TypeTransformer<?, ?> transformer) {
this.transformers.add(transformer);
transformers.computeIfAbsent(transformer.getInputType(), key -> new HashMap<>())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could worth to add a warning log in case of transformer override

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already did, thanks.

Comment on lines +62 to +81
private Optional<TypeTransformer<?, ?>> findTransformer(Object input, Class<?> outputType) {
var inputTypes = transformers.entrySet().stream()
.filter(entry -> entry.getKey().isInstance(input))
.filter(entry -> entry.getValue().containsKey(outputType))
.map(Map.Entry::getKey)
.toList();

var mostSpecificInputTypes = inputTypes.stream()
.filter(candidate -> inputTypes.stream()
.noneMatch(other -> !candidate.equals(other) && candidate.isAssignableFrom(other)))
.toList();

if (mostSpecificInputTypes.size() > 1) {
throw new EdcException(format("Ambiguous transformers registered for %s -> %s", input.getClass(), outputType));
}

return mostSpecificInputTypes.stream()
.findFirst()
.map(inputType -> transformers.get(inputType).get(outputType));
}

@ndr-brt ndr-brt Jul 31, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this logic is not wrong but I think it could be written in a more readable way - and slightly more performant, by avoiding multiple iterations over inputTypes, using streams reduce function:

    private Optional<TypeTransformer<?, ?>> findTransformer(Object input, Class<?> outputType) {
        return transformers.entrySet().stream()
                .filter(entry -> entry.getKey().isInstance(input))
                .filter(entry -> entry.getValue().containsKey(outputType))
                .map(Map.Entry::getKey)
                .map(Optional::of)
                .reduce(Optional.empty(), (current, candidate) -> {
                    if (current.isEmpty()) {
                        return candidate;
                    }

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

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

                    throw new EdcException(format("Ambiguous transformers registered for %s -> %s", input.getClass(), outputType));
                })
                .map(transformers::get)
                .map(it -> it.get(outputType));
    }

so the "most specific" logic emerges in the reduce function itself:

  • set the first item as current
  • is the candidate a supertype of current? ignore it
  • is the candidate a subtype of current? set it as current
  • neither of the two? it means that it's a type that's on a different hierarchy: throw exception

the reduce function could also be extracted and called findMostSpecificInputType

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your implementation is cleaner so I applied it. thanks

@mokhairymahmoud
mokhairymahmoud force-pushed the feat/transformerRegistry branch from d1f66f2 to 705fd59 Compare August 3, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactoring Cleaning up code and dependencies

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants