diff --git a/querydsl-core/src/main/java/com/mysema/query/types/path/PathBuilderValidator.java b/querydsl-core/src/main/java/com/mysema/query/types/path/PathBuilderValidator.java index 4b27946f2..edad71b04 100644 --- a/querydsl-core/src/main/java/com/mysema/query/types/path/PathBuilderValidator.java +++ b/querydsl-core/src/main/java/com/mysema/query/types/path/PathBuilderValidator.java @@ -13,10 +13,14 @@ */ package com.mysema.query.types.path; +import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Map; import com.google.common.primitives.Primitives; import com.mysema.util.BeanUtils; +import com.mysema.util.ReflectionUtils; /** * PathBuilderValidator validates PathBuilder properties at creation time @@ -44,7 +48,14 @@ public interface PathBuilderValidator { public Class validate(Class parent, String property, Class propertyType) { while (!parent.equals(Object.class)) { try { - return (Class) parent.getDeclaredField(property).getType(); + Field field = parent.getDeclaredField(property); + if (Map.class.isAssignableFrom(field.getType())) { + return (Class) ReflectionUtils.getTypeParameterAsClass(field.getGenericType(), 1); + } else if (Collection.class.isAssignableFrom(field.getType())) { + return (Class) ReflectionUtils.getTypeParameterAsClass(field.getGenericType(), 0); + } else { + return (Class) Primitives.wrap(field.getType()); + } } catch (NoSuchFieldException e) { parent = parent.getSuperclass(); } @@ -60,7 +71,17 @@ public interface PathBuilderValidator { if (getter == null && Primitives.wrap(propertyType).equals(Boolean.class)) { getter = BeanUtils.getAccessor("is", property, parent); } - return getter != null ? (Class) getter.getReturnType() : null; + if (getter != null) { + if (Map.class.isAssignableFrom(getter.getReturnType())) { + return (Class) ReflectionUtils.getTypeParameterAsClass(getter.getGenericReturnType(), 1); + } else if (Collection.class.isAssignableFrom(getter.getReturnType())) { + return (Class) ReflectionUtils.getTypeParameterAsClass(getter.getGenericReturnType(), 0); + } else { + return (Class) Primitives.wrap(getter.getReturnType()); + } + } else { + return null; + } } }; diff --git a/querydsl-core/src/test/java/com/mysema/query/types/path/PathBuilderValidatorTest.java b/querydsl-core/src/test/java/com/mysema/query/types/path/PathBuilderValidatorTest.java index 8f1751bae..d66ca2aa3 100644 --- a/querydsl-core/src/test/java/com/mysema/query/types/path/PathBuilderValidatorTest.java +++ b/querydsl-core/src/test/java/com/mysema/query/types/path/PathBuilderValidatorTest.java @@ -1,18 +1,26 @@ package com.mysema.query.types.path; +import java.util.Collection; +import java.util.Map; + import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; public class PathBuilderValidatorTest { public static class Customer { String name; + Collection collection; + Map map; } public static class ExtendedCustomer extends Customer {} public static class Project { public String getName() { return ""; } + public Collection getCollection() { return null; } + public Map getMap() { return null; } } public static class ExtendedProject extends Project { @@ -21,16 +29,18 @@ public class PathBuilderValidatorTest { @Test public void Default() { - assertNotNull(PathBuilderValidator.DEFAULT.validate(Customer.class, "name", String.class)); - assertNotNull(PathBuilderValidator.DEFAULT.validate(ExtendedCustomer.class, "name", String.class)); - assertNotNull(PathBuilderValidator.DEFAULT.validate(Project.class, "name", String.class)); - assertNotNull(PathBuilderValidator.DEFAULT.validate(ExtendedProject.class, "name", String.class)); + assertEquals(String.class, PathBuilderValidator.DEFAULT.validate(Customer.class, "name", String.class)); + assertEquals(String.class, PathBuilderValidator.DEFAULT.validate(ExtendedCustomer.class, "name", String.class)); + assertEquals(String.class, PathBuilderValidator.DEFAULT.validate(Project.class, "name", String.class)); + assertEquals(String.class, PathBuilderValidator.DEFAULT.validate(ExtendedProject.class, "name", String.class)); } @Test public void Fields() { - assertNotNull(PathBuilderValidator.FIELDS.validate(Customer.class, "name", String.class)); - assertNotNull(PathBuilderValidator.FIELDS.validate(ExtendedCustomer.class, "name", String.class)); + assertEquals(String.class, PathBuilderValidator.FIELDS.validate(Customer.class, "name", String.class)); + assertEquals(String.class, PathBuilderValidator.FIELDS.validate(ExtendedCustomer.class, "name", String.class)); + assertEquals(Integer.class, PathBuilderValidator.FIELDS.validate(Customer.class, "collection", Collection.class)); + assertEquals(Integer.class, PathBuilderValidator.FIELDS.validate(Customer.class, "map", Map.class)); assertNull(PathBuilderValidator.FIELDS.validate(Project.class, "name", String.class)); assertNull(PathBuilderValidator.FIELDS.validate(ExtendedProject.class, "name", String.class)); } @@ -39,8 +49,10 @@ public class PathBuilderValidatorTest { public void Properties() { assertNull(PathBuilderValidator.PROPERTIES.validate(Customer.class, "name", String.class)); assertNull(PathBuilderValidator.PROPERTIES.validate(ExtendedCustomer.class, "name", String.class)); - assertNotNull(PathBuilderValidator.PROPERTIES.validate(Project.class, "name", String.class)); - assertNotNull(PathBuilderValidator.PROPERTIES.validate(ExtendedProject.class, "name", String.class)); - assertNotNull(PathBuilderValidator.PROPERTIES.validate(ExtendedProject.class, "started", Boolean.class)); + assertEquals(String.class, PathBuilderValidator.PROPERTIES.validate(Project.class, "name", String.class)); + assertEquals(String.class, PathBuilderValidator.PROPERTIES.validate(ExtendedProject.class, "name", String.class)); + assertEquals(Boolean.class, PathBuilderValidator.PROPERTIES.validate(ExtendedProject.class, "started", Boolean.class)); + assertEquals(Integer.class, PathBuilderValidator.PROPERTIES.validate(Project.class, "collection", Collection.class)); + assertEquals(Integer.class, PathBuilderValidator.PROPERTIES.validate(Project.class, "map", Map.class)); } } diff --git a/querydsl-jpa/src/main/java/com/mysema/query/jpa/support/JPAPathBuilderValidator.java b/querydsl-jpa/src/main/java/com/mysema/query/jpa/support/JPAPathBuilderValidator.java index aba0a0da5..70b93ba6a 100644 --- a/querydsl-jpa/src/main/java/com/mysema/query/jpa/support/JPAPathBuilderValidator.java +++ b/querydsl-jpa/src/main/java/com/mysema/query/jpa/support/JPAPathBuilderValidator.java @@ -14,8 +14,12 @@ package com.mysema.query.jpa.support; import javax.persistence.EntityManager; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.Metamodel; +import javax.persistence.metamodel.PluralAttribute; +import com.google.common.primitives.Primitives; import com.mysema.query.types.path.PathBuilderValidator; /** @@ -36,7 +40,13 @@ public class JPAPathBuilderValidator implements PathBuilderValidator { @Override public Class validate(Class parent, String property, Class propertyType) { try { - return (Class)metamodel.managedType(parent).getAttribute(property).getJavaType(); + ManagedType managedType = metamodel.managedType(parent); + Attribute attribute = managedType.getAttribute(property); + if (attribute instanceof PluralAttribute) { + return ((PluralAttribute)attribute).getElementType().getJavaType(); + } else { + return Primitives.wrap(attribute.getJavaType()); + } } catch (IllegalArgumentException e) { return null; } diff --git a/querydsl-jpa/src/test/java/com/mysema/query/jpa/support/JPAPathBuilderValidatorTest.java b/querydsl-jpa/src/test/java/com/mysema/query/jpa/support/JPAPathBuilderValidatorTest.java index ea97e4137..0b3d5af93 100644 --- a/querydsl-jpa/src/test/java/com/mysema/query/jpa/support/JPAPathBuilderValidatorTest.java +++ b/querydsl-jpa/src/test/java/com/mysema/query/jpa/support/JPAPathBuilderValidatorTest.java @@ -2,12 +2,14 @@ package com.mysema.query.jpa.support; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; +import java.util.Collection; import com.mysema.query.jpa.domain.Cat; import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; public class JPAPathBuilderValidatorTest { @@ -26,7 +28,9 @@ public class JPAPathBuilderValidatorTest { @Test public void validate() { JPAPathBuilderValidator validator = new JPAPathBuilderValidator(entityManagerFactory.getMetamodel()); - assertNotNull(validator.validate(Cat.class, "name", String.class)); + assertEquals(String.class, validator.validate(Cat.class, "name", String.class)); + assertEquals(Cat.class, validator.validate(Cat.class, "kittens", Collection.class)); + assertEquals(Cat.class, validator.validate(Cat.class, "mate", Cat.class)); assertNull(validator.validate(Cat.class, "xxx", String.class)); assertNull(validator.validate(Object.class, "name", String.class)); }