-
-
Notifications
You must be signed in to change notification settings - Fork 45
Draft: Issue #69 | Add ResolvedTypeMapper to convert ResolvedType into Type #103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Luc-Veldhuis
wants to merge
3
commits into
FasterXML:main
Choose a base branch
from
Luc-Veldhuis:luc-veldhuis/69-resolvedtype-to-java-type
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+476
−0
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
209 changes: 209 additions & 0 deletions
209
src/main/java/com/fasterxml/classmate/ResolvedTypeMapper.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,209 @@ | ||
| package com.fasterxml.classmate; | ||
|
|
||
| import com.fasterxml.classmate.types.ResolvedArrayType; | ||
| import com.fasterxml.classmate.types.ResolvedRecursiveType; | ||
|
|
||
| import java.io.Serializable; | ||
| import java.lang.reflect.GenericArrayType; | ||
| import java.lang.reflect.ParameterizedType; | ||
| import java.lang.reflect.Type; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.List; | ||
| import java.util.Objects; | ||
| import java.util.stream.Collectors; | ||
|
|
||
|
|
||
| /** | ||
| * Utility for converting a {@link ResolvedType} into a standard Java {@link Type} | ||
| * that can be used with the reflection API. | ||
| * | ||
| * <p><strong>Limitations:</strong></p> | ||
| * <ul> | ||
| * <li><b>Type variables and wildcards are not fully supported.</b> | ||
| * Since {@link ResolvedType} does not preserve full type variable or wildcard details, | ||
| * this mapper resolves them to their <em>upper bound</em> (or {@link Object} if no upper bound is known).</li> | ||
| * <li>For example: | ||
| * <ul> | ||
| * <li>A field declared as {@code E extends List} will map to {@code List} when the type is unbound.</li> | ||
| * <li>A wildcard like {@code ? super List} or a type variable like {@code E super List} will map to {@code Object}.</li> | ||
| * <li>If a concrete type binding is provided in the {@link TypeBindings}, | ||
| * for example {@code E extends List} bound to {@code ArrayList}, | ||
| * this mapper will return {@code ArrayList}.</li> | ||
| * </ul> | ||
| * </li> | ||
| * </ul> | ||
| * | ||
| * <p> | ||
| * For further discussion, see | ||
| * <a href="https://github.com/FasterXML/java-classmate/issues/69">issue #69</a>. | ||
| * </p> | ||
| */ | ||
|
|
||
| @SuppressWarnings("serial") | ||
| public class ResolvedTypeMapper implements Serializable { | ||
|
|
||
| private static final long serialVersionUID = 1L; | ||
|
|
||
| /** | ||
| * Method for mapping {@link ResolvedType} to java types. | ||
|
|
||
| * @param resolvedType The resolved type to map to a java {@link Type} | ||
| * @return The type with all generics resolved, OR with the generics replaced with the upper bounds AND with all wildcards resolved to the upper bound. | ||
| */ | ||
| public Type map(ResolvedType resolvedType) { | ||
| if (resolvedType instanceof ResolvedArrayType) { | ||
| ResolvedArrayType arrayType = (ResolvedArrayType) resolvedType; | ||
| ResolvedType arrayElementType = arrayType.getArrayElementType(); | ||
| if (arrayElementType == null) { | ||
| throw new IllegalStateException("Missing array element type"); | ||
| } | ||
| Type elementType = map(arrayElementType); | ||
| //GenericArrayType is only used for parameterized types or TypeVariables, but we don't have TypeVariables | ||
| if (elementType instanceof ParameterizedType) { | ||
| return new GenericArrayTypeImpl(elementType); | ||
| } | ||
| return arrayType.getErasedType(); | ||
| } | ||
| // Extract recursive type | ||
| if (resolvedType instanceof ResolvedRecursiveType) { | ||
| ResolvedRecursiveType recursiveType = (ResolvedRecursiveType) resolvedType; | ||
| ResolvedType selfReferencedType = recursiveType.getSelfReferencedType(); | ||
| if (selfReferencedType == null) { | ||
| throw new IllegalStateException("Missing self referenced type"); | ||
| } | ||
| return map(selfReferencedType); | ||
| } | ||
| // no generics present, so the erased type is equal to the real type | ||
| if (resolvedType.getTypeParameters() == null || resolvedType.getTypeParameters().isEmpty()) { | ||
| return resolvedType.getErasedType(); | ||
| } | ||
| // Parameters are present, so we need to create a parameterized | ||
| // Wildcard types are not supported, since we store the upperbound | ||
| return _mapParameterizedType(resolvedType); | ||
| } | ||
|
|
||
| private ParameterizedTypeImpl _mapParameterizedType(ResolvedType objectType) { | ||
| Class<?> erasedType = objectType.getErasedType(); | ||
| List<Type> list = new ArrayList<>(); | ||
| for (ResolvedType resolvedType : objectType.getTypeParameters()) { | ||
| Type mappedArrayType = map(resolvedType); | ||
| list.add(mappedArrayType); | ||
| } | ||
| return new ParameterizedTypeImpl(erasedType, list.toArray(new Type[0]), erasedType.getEnclosingClass()); | ||
| } | ||
|
|
||
| /** | ||
| * Implementation of ParameterizedType for classmate type creation | ||
| */ | ||
| static final class ParameterizedTypeImpl implements ParameterizedType { | ||
| private final Type rawType; | ||
| private final Type[] actualTypeArguments; | ||
| private final Type ownerType; | ||
|
|
||
| private ParameterizedTypeImpl(Type rawType, Type[] actualTypeArguments, Type ownerType) { | ||
| this.rawType = rawType; | ||
| this.actualTypeArguments = actualTypeArguments; | ||
| this.ownerType = ownerType; | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
| @Override | ||
| public Type[] getActualTypeArguments() { | ||
| return actualTypeArguments; | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
| @Override | ||
| public Type getRawType() { | ||
| return rawType; | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
| @Override | ||
| public Type getOwnerType() { | ||
| return ownerType; | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (!(o instanceof ParameterizedType)) { | ||
| return false; | ||
| } | ||
| ParameterizedType that = (ParameterizedType) o; | ||
| return Objects.equals(rawType, that.getRawType()) && Objects.deepEquals(actualTypeArguments, that.getActualTypeArguments()) && Objects.equals(ownerType, that.getOwnerType()); | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(rawType, Arrays.hashCode(actualTypeArguments), ownerType); | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
| @Override | ||
| public String toString() { | ||
| return rawType + "<" + Arrays.stream(actualTypeArguments).map(Type::getTypeName).collect(Collectors.joining(", ")) + ">"; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Implementation of GenericArrayType for classmate type creation | ||
| */ | ||
| static final class GenericArrayTypeImpl implements GenericArrayType { | ||
| private final Type genericComponentType; | ||
|
|
||
| private GenericArrayTypeImpl(Type genericComponentType) { | ||
| this.genericComponentType = genericComponentType; | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
| @Override | ||
| public Type getGenericComponentType() { | ||
| return genericComponentType; | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (!(o instanceof GenericArrayType)) { | ||
| return false; | ||
| } | ||
| GenericArrayType that = (GenericArrayType) o; | ||
| return Objects.equals(genericComponentType, that.getGenericComponentType()); | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hashCode(genericComponentType); | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
| @Override | ||
| public String toString() { | ||
| return genericComponentType.getTypeName() + "[]"; | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably list specific
Types produced (GenericArrayType,ParameterizedType).And also, without generics,
Classes too?