From 255b7076b8a34b2b0a50f76bc766e4219843c97a Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 2 Nov 2009 16:46:17 +0000 Subject: [PATCH] HHH-4202 - Implement JPA 2.0 metamodel APIs git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@17886 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../metamodel/AbstractIdentifiableType.java | 14 ++ .../ejb/metamodel/MetadataContext.java | 62 +++++++- .../hibernate/ejb/test/metadata/Animal.java | 23 +++ .../org/hibernate/ejb/test/metadata/Cat.java | 23 +++ .../hibernate/ejb/test/metadata/Cattish.java | 23 +++ .../org/hibernate/ejb/test/metadata/Dog.java | 23 +++ .../hibernate/ejb/test/metadata/Feline.java | 23 +++ .../ejb/test/metadata/StaticMetadataTest.java | 134 ++++++++++++++++++ .../hibernate/ejb/test/metadata/Thing.java | 23 +++ 9 files changed, 345 insertions(+), 3 deletions(-) create mode 100644 entitymanager/src/test/java/org/hibernate/ejb/test/metadata/StaticMetadataTest.java diff --git a/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractIdentifiableType.java b/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractIdentifiableType.java index 5767eb9c81..bca9d7a9ea 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractIdentifiableType.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractIdentifiableType.java @@ -189,6 +189,10 @@ public abstract class AbstractIdentifiableType return isVersioned; } + public boolean hasDeclaredVersionAttribute() { + return isVersioned && version != null; + } + /** * {@inheritDoc} */ @@ -222,6 +226,16 @@ public abstract class AbstractIdentifiableType return ( SingularAttribute ) version; } + /** + * For used to retrieve the declared version when populating the static metamodel. + * + * @return The declared + */ + public SingularAttribute getDeclaredVersion() { + checkDeclaredVersion(); + return version; + } + /** * Centralized check to ensure the version (if one) is actually declared on the class mapped here, as opposed to a * super class. diff --git a/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java b/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java index 170c763875..e43ca0d43c 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java @@ -29,16 +29,17 @@ import java.util.Map; import java.util.Set; import java.util.List; import java.util.ArrayList; +import java.lang.reflect.Field; import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.SingularAttribute; -import javax.swing.*; +import javax.persistence.metamodel.IdentifiableType; import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; +import org.hibernate.mapping.Component; import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.annotations.common.AssertionFailure; -import org.hibernate.AnnotationException; /** * Defines a context for storing information during the building of the {@link MetamodelImpl}. @@ -163,6 +164,12 @@ class MetadataContext { Iterator properties = ( Iterator ) safeMapping.getDeclaredPropertyIterator(); while ( properties.hasNext() ) { final Property property = properties.next(); + if ( property.getValue() == safeMapping.getIdentifierMapper() ) { + // property represents special handling for id-class mappings but we have already + // accounted for the embedded property mappings in #applyIdMetadata && + // #buildIdClassAttributes + continue; + } final Attribute attribute = attributeFactory.buildAttribute( jpa2Mapping, property, true ); jpa2Mapping.getBuilder().addAttribute( attribute ); } @@ -190,8 +197,13 @@ class MetadataContext { throw new AssertionFailure( "Unexpected mapping type: " + mapping.getClass() ); } } + + for ( EmbeddableTypeImpl embeddable : embeddables.values() ) { + populateStaticMetamodel( embeddable ); + } } + private void applyIdMetadata(PersistentClass persistentClass, EntityTypeImpl jpaEntityType) { if ( persistentClass.hasIdentifierProperty() ) { final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty(); @@ -289,11 +301,55 @@ class MetadataContext { private final Set processedMetamodelClasses = new HashSet(); private void registerAttributes(Class metamodelClass, AbstractManagedType managedType) { - if ( processedMetamodelClasses.add( metamodelClass ) ) { + if ( ! processedMetamodelClasses.add( metamodelClass ) ) { return; } // push the attributes on to the metamodel class... + for ( Attribute attribute : managedType.getDeclaredAttributes() ) { + registerAttribute( metamodelClass, attribute ); + } + + if ( IdentifiableType.class.isInstance( managedType ) ) { + final AbstractIdentifiableType entityType = ( AbstractIdentifiableType ) managedType; + + // handle version + if ( entityType.hasDeclaredVersionAttribute() ) { + registerAttribute( metamodelClass, entityType.getDeclaredVersion() ); + } + + // handle id-class mappings specially + if ( ! entityType.hasSingleIdAttribute() ) { + final Set> attributes = entityType.getIdClassAttributes(); + if ( attributes != null ) { + for ( SingularAttribute attribute : attributes ) { + registerAttribute( metamodelClass, attribute ); + } + } + } + } + } + + private void registerAttribute(Class metamodelClass, Attribute attribute) { + final String name = attribute.getName(); + try { + Field field = metamodelClass.getDeclaredField( name ); + field.setAccessible( true ); // should be public anyway, but to be sure... + field.set( null, attribute ); + } + catch ( NoSuchFieldException e ) { + // todo : exception type? + throw new AssertionFailure( + "Unable to locate static metamodel field : " + metamodelClass.getName() + '#' + name + ); + } + catch ( IllegalAccessException e ) { + // todo : exception type? + throw new AssertionFailure( + "Unable to inject static metamodel attribute : " + metamodelClass.getName() + '#' + name, + e + ); + } } public MappedSuperclassTypeImpl locateMappedSuperclassType(MappedSuperclass mappedSuperclass) { diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Animal.java b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Animal.java index 5e54db40ad..22d8d91571 100644 --- a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Animal.java +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Animal.java @@ -1,3 +1,26 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @author tags or express + * copyright attribution statements applied by the authors. All + * third-party contributions are distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ package org.hibernate.ejb.test.metadata; import javax.persistence.MappedSuperclass; diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cat.java b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cat.java index 73743c457f..b1d979714d 100644 --- a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cat.java +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cat.java @@ -1,3 +1,26 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @author tags or express + * copyright attribution statements applied by the authors. All + * third-party contributions are distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ package org.hibernate.ejb.test.metadata; import javax.persistence.Entity; diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cattish.java b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cattish.java index c7f1ae5cc8..94091010ea 100644 --- a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cattish.java +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cattish.java @@ -1,3 +1,26 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @author tags or express + * copyright attribution statements applied by the authors. All + * third-party contributions are distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ package org.hibernate.ejb.test.metadata; import javax.persistence.MappedSuperclass; diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Dog.java b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Dog.java index b319840d3d..97e51d0d6b 100644 --- a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Dog.java +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Dog.java @@ -1,3 +1,26 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @author tags or express + * copyright attribution statements applied by the authors. All + * third-party contributions are distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ package org.hibernate.ejb.test.metadata; import javax.persistence.Entity; diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Feline.java b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Feline.java index fafc2e82e0..e0728bc59d 100644 --- a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Feline.java +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Feline.java @@ -1,3 +1,26 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @author tags or express + * copyright attribution statements applied by the authors. All + * third-party contributions are distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ package org.hibernate.ejb.test.metadata; import javax.persistence.Entity; diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/StaticMetadataTest.java b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/StaticMetadataTest.java new file mode 100644 index 0000000000..529ec2365b --- /dev/null +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/StaticMetadataTest.java @@ -0,0 +1,134 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @author tags or express + * copyright attribution statements applied by the authors. All + * third-party contributions are distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.test.metadata; + +import java.util.Set; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.Bindable; +import javax.persistence.metamodel.EmbeddableType; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.Type; + +import org.hibernate.ejb.test.TestCase; + +/** + * @author Steve Ebersole + */ +public class StaticMetadataTest extends TestCase { + + public void testInjections() throws Exception { + // Address (embeddable) + assertNotNull( Address_.address1 ); + assertNotNull( Address_.address2 ); + assertNotNull( Address_.city ); + final EmbeddableType
addressType = (EmbeddableType
) House_.address.getType(); + assertEquals( addressType.getDeclaredSingularAttribute( "address1" ), Address_.address1 ); + assertEquals( addressType.getDeclaredSingularAttribute( "address2" ), Address_.address2 ); + assertTrue( Address_.address1.isOptional() ); + assertFalse( Address_.address2.isOptional() ); + + // Animal (mapped superclass) + assertNotNull( Animal_.id ); + assertTrue( Animal_.id.isId() ); + assertEquals( Long.class, Animal_.id.getJavaType() ); + assertNotNull( Animal_.legNbr ); + assertEquals( Integer.class, Animal_.legNbr.getJavaType() ); + + // Cat (hierarchy) + assertNotNull( Cat_.id ); + assertNotNull( Cat_.id.isId() ); + assertEquals( Animal.class, Cat_.id.getJavaMember().getDeclaringClass() ); + assertNotNull( Cat_.nickname ); + + // FoodItem + assertNotNull( FoodItem_.version ); + assertTrue( FoodItem_.version.isVersion() ); + + // Fridge + assertNotNull( Fridge_.id ); + assertTrue( Fridge_.id.isId() ); + assertEquals( Long.class, Fridge_.id.getJavaType() ); + assertNotNull( Fridge_.temperature ); + assertEquals( "temperature", Fridge_.temperature.getName() ); + assertEquals( Fridge.class, Fridge_.temperature.getDeclaringType().getJavaType() ); + assertEquals( Integer.class, Fridge_.temperature.getJavaType() ); + assertEquals( Integer.class, Fridge_.temperature.getBindableJavaType() ); + assertEquals( Integer.class, Fridge_.temperature.getType().getJavaType() ); + assertEquals( Bindable.BindableType.SINGULAR_ATTRIBUTE, Fridge_.temperature.getBindableType() ); + assertEquals( Type.PersistenceType.BASIC, Fridge_.temperature.getType().getPersistenceType() ); + assertEquals( Attribute.PersistentAttributeType.BASIC, Fridge_.temperature.getPersistentAttributeType() ); + assertFalse( Fridge_.temperature.isId() ); + assertFalse( Fridge_.temperature.isOptional() ); + assertFalse( Fridge_.temperature.isAssociation() ); + assertFalse( Fridge_.temperature.isCollection() ); + assertFalse( Fridge_.brand.isOptional() ); + + // House (embedded id) + assertNotNull( House_.key ); + assertTrue( House_.key.isId() ); + assertEquals( Attribute.PersistentAttributeType.EMBEDDED, House_.key.getPersistentAttributeType() ); + assertNotNull( House_.address ); + assertEquals( Attribute.PersistentAttributeType.EMBEDDED, House_.address.getPersistentAttributeType() ); + assertFalse( House_.address.isCollection() ); + assertFalse( House_.address.isAssociation() ); + assertNotNull( House_.rooms ); + assertTrue( House_.rooms.isAssociation() ); + assertTrue( House_.rooms.isCollection() ); + assertEquals( Attribute.PersistentAttributeType.ELEMENT_COLLECTION, House_.rooms.getPersistentAttributeType() ); + assertEquals( Room.class, House_.rooms.getBindableJavaType() ); + assertEquals( Bindable.BindableType.PLURAL_ATTRIBUTE, House_.rooms.getBindableType() ); + assertEquals( Set.class, House_.rooms.getJavaType() ); + assertEquals( PluralAttribute.CollectionType.SET, House_.rooms.getCollectionType() ); + assertEquals( Type.PersistenceType.EMBEDDABLE, House_.rooms.getElementType().getPersistenceType() ); + assertNotNull( House_.roomsByName ); + assertEquals( String.class, House_.roomsByName.getKeyJavaType() ); + assertEquals( Type.PersistenceType.BASIC, House_.roomsByName.getKeyType().getPersistenceType() ); + assertEquals( PluralAttribute.CollectionType.MAP, House_.roomsByName.getCollectionType() ); + assertNotNull( House_.roomsBySize ); + assertEquals( Type.PersistenceType.EMBEDDABLE, House_.roomsBySize.getElementType().getPersistenceType() ); + assertEquals( PluralAttribute.CollectionType.LIST, House_.roomsBySize.getCollectionType() ); + + // Person (mapped id) + assertNotNull( Person_.firstName ); + assertNotNull( Person_.lastName ); + assertTrue( Person_.firstName.isId() ); + assertTrue( Person_.lastName.isId() ); + assertTrue( Person_.lastName.isId() ); + } + + @Override + public Class[] getAnnotatedClasses() { + return new Class[]{ + Fridge.class, + FoodItem.class, + Person.class, + House.class, + Dog.class, + Cat.class, + Cattish.class, + Feline.class + }; + } + +} \ No newline at end of file diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Thing.java b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Thing.java index b73539e811..8e9bf3c9ab 100644 --- a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Thing.java +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Thing.java @@ -1,3 +1,26 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @author tags or express + * copyright attribution statements applied by the authors. All + * third-party contributions are distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ package org.hibernate.ejb.test.metadata; import javax.persistence.MappedSuperclass;