diff --git a/core/src/main/java/dev/morphia/mapping/codec/MorphiaCollectionPropertyCodecProvider.java b/core/src/main/java/dev/morphia/mapping/codec/MorphiaCollectionPropertyCodecProvider.java index 8fa513fe9d2..b51a9b7cf5d 100644 --- a/core/src/main/java/dev/morphia/mapping/codec/MorphiaCollectionPropertyCodecProvider.java +++ b/core/src/main/java/dev/morphia/mapping/codec/MorphiaCollectionPropertyCodecProvider.java @@ -34,7 +34,7 @@ public Codec get(TypeWithTypeParameters type, PropertyCodecRegistry re } catch (CodecConfigurationException e) { if (valueType.getType().equals(Object.class)) { try { - return (Codec) registry.get(TypeData.builder(Collection.class).build()); + return (Codec) registry.get(TypeData.get(Collection.class)); } catch (CodecConfigurationException e1) { // Ignore and return original exception } diff --git a/core/src/main/java/dev/morphia/mapping/codec/MorphiaMapPropertyCodecProvider.java b/core/src/main/java/dev/morphia/mapping/codec/MorphiaMapPropertyCodecProvider.java index b3064e6d98a..85bd81050a7 100644 --- a/core/src/main/java/dev/morphia/mapping/codec/MorphiaMapPropertyCodecProvider.java +++ b/core/src/main/java/dev/morphia/mapping/codec/MorphiaMapPropertyCodecProvider.java @@ -40,7 +40,7 @@ public Codec get(TypeWithTypeParameters type, PropertyCodecRegistry re } catch (CodecConfigurationException e) { if (valueType.getType().equals(Object.class)) { try { - return (Codec) registry.get(TypeData.builder(Map.class).build()); + return (Codec) registry.get(TypeData.get(Map.class)); } catch (CodecConfigurationException e1) { // Ignore and return original exception } diff --git a/core/src/main/java/dev/morphia/mapping/codec/MorphiaPropertyCodecProvider.java b/core/src/main/java/dev/morphia/mapping/codec/MorphiaPropertyCodecProvider.java index 6cb86796096..a71862d983f 100644 --- a/core/src/main/java/dev/morphia/mapping/codec/MorphiaPropertyCodecProvider.java +++ b/core/src/main/java/dev/morphia/mapping/codec/MorphiaPropertyCodecProvider.java @@ -19,6 +19,6 @@ public abstract class MorphiaPropertyCodecProvider implements PropertyCodecProvi protected TypeWithTypeParameters getType(List> typeParameters, int position) { return typeParameters.size() > position ? typeParameters.get(position) - : TypeData.builder(Object.class).build(); + : TypeData.get(Object.class); } } diff --git a/core/src/main/java/dev/morphia/mapping/codec/pojo/EntityModelBuilder.java b/core/src/main/java/dev/morphia/mapping/codec/pojo/EntityModelBuilder.java index e54858b33cd..f6808230afb 100644 --- a/core/src/main/java/dev/morphia/mapping/codec/pojo/EntityModelBuilder.java +++ b/core/src/main/java/dev/morphia/mapping/codec/pojo/EntityModelBuilder.java @@ -222,7 +222,7 @@ public TypeData getTypeData(Class type, TypeData suggested, Type generi if (map != null) { Type mapped = map.get(((TypeVariable) genericType).getName()); if (mapped != null) { - suggested = TypeData.newInstance(mapped); + suggested = TypeData.get(mapped); } } } diff --git a/core/src/main/java/dev/morphia/mapping/codec/pojo/TypeData.java b/core/src/main/java/dev/morphia/mapping/codec/pojo/TypeData.java index a5eee08d52f..b176d97deb1 100644 --- a/core/src/main/java/dev/morphia/mapping/codec/pojo/TypeData.java +++ b/core/src/main/java/dev/morphia/mapping/codec/pojo/TypeData.java @@ -35,9 +35,26 @@ public class TypeData implements TypeWithTypeParameters { private final Class type; - private final List> typeParameters; + private final List> typeParameters = new ArrayList<>(); private boolean array; + /** + * Creates a new TypeData with the concrete type and type parameters around it. + *

+ * e.g., List<Address> would be + * + *

+     * 
+     * new TypeData(Address.class, TypeData.builder(List.class).build())
+     * 
+     * 
+ * + * @param type the type + */ + public TypeData(Class type) { + this.type = type; + } + /** * Creates a new TypeData with the concrete type and type parameters around it. *

@@ -54,7 +71,7 @@ public class TypeData implements TypeWithTypeParameters { */ public TypeData(Class type, List> typeParameters) { this.type = type; - this.typeParameters = typeParameters; + this.typeParameters.addAll(typeParameters); } /** @@ -69,13 +86,13 @@ public static Builder builder(Class type) { } @SuppressWarnings({ "unchecked", "rawtypes" }) - private static TypeData getTypeData(Type type) { + public static TypeData get(Type type) { if (type instanceof ParameterizedType) { ParameterizedType pType = (ParameterizedType) type; TypeParameters parameters = TypeParameters.of(pType); Builder paramBuilder = TypeData.builder((Class) pType.getRawType()); for (Type argType : parameters) { - paramBuilder.addTypeParameter(getTypeData(argType)); + paramBuilder.addTypeParameter(get(argType)); } return paramBuilder.build(); } else if (type instanceof WildcardType) { @@ -84,18 +101,18 @@ private static TypeData getTypeData(Type type) { Type[] bounds = upperBounds != null ? upperBounds : wildcardType.getLowerBounds(); - return WildCardTypeData.builder(getTypeData(bounds[0]), upperBounds != null).build(); + return new WildCardTypeData(get(bounds[0]), upperBounds != null); } else if (type instanceof TypeVariable) { return TypeData.builder(Object.class).build(); } else if (type instanceof Class) { - Builder builder = TypeData.builder((Class) type); + var typeData = new TypeData((Class) type); for (Type argType : TypeParameters.of(type)) { - builder.addTypeParameter(getTypeData(argType)); + typeData.typeParameters.add(argType.equals(type) ? type : get(argType)); } - return builder.build(); + return typeData; } else if (type instanceof GenericArrayType) { GenericArrayType arrayType = (GenericArrayType) type; - TypeData typeData = getTypeData(arrayType.getGenericComponentType()); + TypeData typeData = get(arrayType.getGenericComponentType()); typeData.setArray(true); return typeData; } @@ -211,8 +228,8 @@ private static String nestedTypeParameters(List> typeParameters) { * @param field the field to analyze * @return the new TypeData information */ - public static TypeData newInstance(Field field) { - return newInstance(field.getGenericType()); + public static TypeData get(Field field) { + return get(field.getGenericType()); } /** @@ -221,7 +238,7 @@ public static TypeData newInstance(Field field) { * @param method the method to analyze * @return the new TypeData information */ - public static TypeData newInstance(Method method) { + public static TypeData get(Method method) { return newInstance(method.getGenericReturnType()); } @@ -243,7 +260,7 @@ public static TypeData newInstance(Type genericType) { * } * return builder.build(); */ - return (TypeData) getTypeData(genericType); + return (TypeData) get(genericType); } /** diff --git a/core/src/main/java/dev/morphia/mapping/codec/pojo/WildCardTypeData.java b/core/src/main/java/dev/morphia/mapping/codec/pojo/WildCardTypeData.java index 8bb0e18f7dc..0b8dce98471 100644 --- a/core/src/main/java/dev/morphia/mapping/codec/pojo/WildCardTypeData.java +++ b/core/src/main/java/dev/morphia/mapping/codec/pojo/WildCardTypeData.java @@ -21,17 +21,6 @@ public class WildCardTypeData extends TypeData { this.upperBound = upperBound; } - /** - * Creates a builder - * - * @param bound - * @param upperBound true if the type parameters represent an upper bound - * @return the new builder - */ - public static Builder builder(TypeData bound, boolean upperBound) { - return new Builder(bound, upperBound); - } - @Override public int hashCode() { return Objects.hash(super.hashCode(), upperBound); @@ -52,52 +41,8 @@ public boolean equals(Object o) { return upperBound == that.upperBound; } - /** - * @return true if the type parameters represent an upper bound - */ - public boolean isUpperBound() { - return upperBound; - } - @Override public String toString() { - /* - * String value = type.getSimpleName(); - * if (!typeParameters.isEmpty()) { - * StringJoiner joiner = new StringJoiner(", ", "<", ">"); - * typeParameters.forEach(t -> { - * joiner.add(t.toString()); - * }); - * value += joiner; - * } - */ - return (upperBound ? "? extends " : "? super ") + super.toString(); } - - /** - * A builder for WildCardTypeData - */ - public static class Builder { - private final boolean upperBound; - private final TypeData typeData; - - /** - * Creates a builder - * - * @param bound - * @param upperBound true if the type parameters represent an upper bound - */ - public Builder(TypeData bound, boolean upperBound) { - this.typeData = bound; - this.upperBound = upperBound; - } - - /** - * @return the new WildCardTypeData - */ - public WildCardTypeData build() { - return new WildCardTypeData(typeData, upperBound); - } - } } diff --git a/core/src/main/java/dev/morphia/mapping/conventions/FieldDiscovery.java b/core/src/main/java/dev/morphia/mapping/conventions/FieldDiscovery.java index 2568ee0ea03..5ca5db02c61 100644 --- a/core/src/main/java/dev/morphia/mapping/conventions/FieldDiscovery.java +++ b/core/src/main/java/dev/morphia/mapping/conventions/FieldDiscovery.java @@ -29,7 +29,7 @@ public void apply(Mapper mapper, EntityModelBuilder builder) { for (Class type : list) { for (Field field : type.getDeclaredFields()) { - TypeData typeData = builder.getTypeData(type, TypeData.newInstance(field), field.getGenericType()); + TypeData typeData = builder.getTypeData(type, TypeData.get(field), field.getGenericType()); try { builder.addProperty() .name(field.getName()) diff --git a/core/src/main/java/dev/morphia/mapping/conventions/MethodDiscovery.java b/core/src/main/java/dev/morphia/mapping/conventions/MethodDiscovery.java index e91a367156e..db8d1bc604f 100644 --- a/core/src/main/java/dev/morphia/mapping/conventions/MethodDiscovery.java +++ b/core/src/main/java/dev/morphia/mapping/conventions/MethodDiscovery.java @@ -62,7 +62,7 @@ private List processMethods(Class type) { private void addProperties(EntityModelBuilder builder, Set properties) { for (Methods methods : properties) { - TypeData typeData = entityModelBuilder.getTypeData(methods.type, TypeData.newInstance(methods.getter), + TypeData typeData = entityModelBuilder.getTypeData(methods.type, TypeData.get(methods.getter), methods.getter.getGenericReturnType()); entityModelBuilder.addProperty() diff --git a/core/src/test/java/dev/morphia/test/mapping/codec/pojo/TypeDataTest.java b/core/src/test/java/dev/morphia/test/mapping/codec/pojo/TypeDataTest.java index cf1d2dc26b4..e93c150f1cb 100644 --- a/core/src/test/java/dev/morphia/test/mapping/codec/pojo/TypeDataTest.java +++ b/core/src/test/java/dev/morphia/test/mapping/codec/pojo/TypeDataTest.java @@ -6,6 +6,8 @@ import java.util.List; import java.util.Locale; +import dev.morphia.annotations.Entity; +import dev.morphia.annotations.Id; import dev.morphia.mapping.codec.pojo.TypeData; import dev.morphia.test.TestBase; import dev.morphia.test.mapping.codec.pojo.generics.FullHashMap; @@ -22,7 +24,7 @@ public class TypeDataTest extends TestBase { @Test public void testWildcards() throws NoSuchFieldException { - TypeData typeData = TypeData.newInstance(WildCard.class.getDeclaredField("listOfLists")); + TypeData typeData = TypeData.get(WildCard.class.getDeclaredField("listOfLists")); assertEquals(typeData.getType(), List.class); List> typeParameters = typeData.getTypeParameters(); @@ -64,10 +66,16 @@ public void testSubtypes() { }); } + @Test + public void testRecursiveTypes() { + TypeData.get(MyEntity.class); + TypeData.get(MyEmbeddedEntity.class); + } + private static void typeData(Class owner, String fieldName, Class fieldType, Class... parameterTypes) throws NoSuchFieldException { Field field = owner.getDeclaredField(fieldName); - TypeData typeData = TypeData.newInstance(field); + TypeData typeData = TypeData.get(field); assertEquals(typeData.getType(), fieldType); List> typeParameters = typeData.getTypeParameters(); assertEquals(typeParameters.size(), parameterTypes.length); @@ -79,4 +87,19 @@ private static void typeData(Class owner, String fieldName, Class fieldTyp private static class WildCard { private List> listOfLists; } + + private static class MongoEntity { + } + + @Entity + private static class MyEmbeddedEntity extends MongoEntity { + } + + @Entity + private static class MyEntity { + @Id + private String id; + private String address; + List embeddedEntities; + } } \ No newline at end of file