HHH-6109 Starting the implementation of a replacement for InheritanceState. The determined mapped classes need to be pre-processed
in order to detmerine inheritance features, default access types, etc
This commit is contained in:
parent
42502e696b
commit
297c703449
|
@ -30,20 +30,22 @@ manifest.mainAttributes(
|
||||||
'Main-Class': 'org.hibernate.Version'
|
'Main-Class': 'org.hibernate.Version'
|
||||||
)
|
)
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
test {
|
sourceSets.main {
|
||||||
// resources inherently exclude sources
|
originalJavaSrcDirs = java.srcDirs
|
||||||
resources {
|
jaxbTargetDir = file( "${buildDir}/generated-src/jaxb" )
|
||||||
setSrcDirs( ['src/test/java','src/test/resources'] )
|
java.srcDir jaxbTargetDir
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// resources inherently exclude sources
|
||||||
|
sourceSets.test.resources {
|
||||||
|
setSrcDirs( ['src/test/java','src/test/resources'] )
|
||||||
}
|
}
|
||||||
|
|
||||||
ideaModule {
|
ideaModule {
|
||||||
sourceDirs.add( file( '$buildDir/generated-src/antlr/main' ) )
|
sourceDirs.add( file( '$buildDir/generated-src/antlr/main' ) )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
task jaxb << {
|
task jaxb << {
|
||||||
jaxbTargetDir = file( "${buildDir}/generated-src/jaxb" )
|
jaxbTargetDir = file( "${buildDir}/generated-src/jaxb" )
|
||||||
jaxbTargetDir.mkdirs()
|
jaxbTargetDir.mkdirs()
|
||||||
|
|
|
@ -21,14 +21,10 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// $Id$
|
|
||||||
|
|
||||||
package org.hibernate.cfg;
|
package org.hibernate.cfg;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum defining deifferent access strategies for accessing entity values.
|
* Enum defining different access strategies for accessing entity values.
|
||||||
*
|
*
|
||||||
* @author Hardy Ferentschik
|
* @author Hardy Ferentschik
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -24,18 +24,14 @@
|
||||||
package org.hibernate.metamodel.source.annotations;
|
package org.hibernate.metamodel.source.annotations;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
import javax.persistence.MappedSuperclass;
|
|
||||||
|
|
||||||
import org.jboss.jandex.AnnotationInstance;
|
import org.jboss.jandex.AnnotationInstance;
|
||||||
import org.jboss.jandex.ClassInfo;
|
import org.jboss.jandex.ClassInfo;
|
||||||
import org.jboss.jandex.DotName;
|
|
||||||
import org.jboss.jandex.Index;
|
import org.jboss.jandex.Index;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.hibernate.AnnotationException;
|
|
||||||
import org.hibernate.AssertionFailure;
|
|
||||||
import org.hibernate.metamodel.source.Metadata;
|
import org.hibernate.metamodel.source.Metadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,10 +44,6 @@ import org.hibernate.metamodel.source.Metadata;
|
||||||
* @todo The annotation index should really be passed at construction time
|
* @todo The annotation index should really be passed at construction time
|
||||||
*/
|
*/
|
||||||
public class AnnotationBinder {
|
public class AnnotationBinder {
|
||||||
public static final DotName ENTITY = DotName.createSimple( Entity.class.getName() );
|
|
||||||
public static final DotName HIBERNATE_ENTITY = DotName.createSimple( org.hibernate.annotations.Entity.class.getName() );
|
|
||||||
public static final DotName MAPPED_SUPER_CLASS = DotName.createSimple( MappedSuperclass.class.getName() );
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger( AnnotationBinder.class );
|
private static final Logger log = LoggerFactory.getLogger( AnnotationBinder.class );
|
||||||
private final Metadata metadata;
|
private final Metadata metadata;
|
||||||
|
|
||||||
|
@ -61,33 +53,30 @@ public class AnnotationBinder {
|
||||||
|
|
||||||
public void bindMappedClasses(Index annotationIndex) {
|
public void bindMappedClasses(Index annotationIndex) {
|
||||||
// need to order our annotated entities into an order we can process
|
// need to order our annotated entities into an order we can process
|
||||||
EntityHierarchyBuilder builder = new EntityHierarchyBuilder();
|
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
|
||||||
List<EntityHierarchy> hierarchies = builder.createEntityHierarchies( annotationIndex );
|
Set<ConfiguredClassHierarchy> hierarchies = builder.createEntityHierarchies( annotationIndex );
|
||||||
|
|
||||||
// now we process each hierarchy one at the time
|
// now we process each hierarchy one at the time
|
||||||
for ( EntityHierarchy hierarchy : hierarchies ) {
|
for ( ConfiguredClassHierarchy hierarchy : hierarchies ) {
|
||||||
Iterator<Entity> iter = hierarchy.iterator();
|
Iterator<ConfiguredClass> iter = hierarchy.iterator();
|
||||||
while ( iter.hasNext() ) {
|
while ( iter.hasNext() ) {
|
||||||
Entity entity = iter.next();
|
ConfiguredClass entity = iter.next();
|
||||||
bindEntity( entity );
|
bindEntity( entity );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bindEntity(Entity entity) {
|
public void bindEntity(ConfiguredClass entity) {
|
||||||
ClassInfo classInfo = entity.getClassInfo();
|
ClassInfo classInfo = entity.getClassInfo();
|
||||||
|
|
||||||
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
|
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
|
||||||
AnnotationInstance jpaEntityAnnotation = getSingleAnnotation( classInfo, ENTITY );
|
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, ConfiguredClass.ENTITY );
|
||||||
AnnotationInstance mappedSuperClassAnnotation = getSingleAnnotation( classInfo, MAPPED_SUPER_CLASS );
|
AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation(
|
||||||
AnnotationInstance hibernateEntityAnnotation = getSingleAnnotation( classInfo, HIBERNATE_ENTITY );
|
classInfo, ConfiguredClass.MAPPED_SUPER_CLASS
|
||||||
|
);
|
||||||
if ( jpaEntityAnnotation != null && mappedSuperClassAnnotation != null ) {
|
AnnotationInstance hibernateEntityAnnotation = JandexHelper.getSingleAnnotation(
|
||||||
throw new AnnotationException(
|
classInfo, ConfiguredClass.HIBERNATE_ENTITY
|
||||||
"An entity cannot be annotated with both @Entity and @MappedSuperclass: "
|
);
|
||||||
+ classInfo.name().toString()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// //TODO: be more strict with secondarytable allowance (not for ids, not for secondary table join columns etc)
|
// //TODO: be more strict with secondarytable allowance (not for ids, not for secondary table join columns etc)
|
||||||
|
@ -307,30 +296,6 @@ public class AnnotationBinder {
|
||||||
// entityBinder.processComplementaryTableDefinitions( clazzToProcess.getAnnotation( org.hibernate.annotations.Table.class ) );
|
// entityBinder.processComplementaryTableDefinitions( clazzToProcess.getAnnotation( org.hibernate.annotations.Table.class ) );
|
||||||
// entityBinder.processComplementaryTableDefinitions( clazzToProcess.getAnnotation( org.hibernate.annotations.Tables.class ) );
|
// entityBinder.processComplementaryTableDefinitions( clazzToProcess.getAnnotation( org.hibernate.annotations.Tables.class ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param classInfo the class info from which to retrieve the annotation instance
|
|
||||||
* @param annotationName the annotation to retrieve from the class info
|
|
||||||
*
|
|
||||||
* @return the single annotation defined on the class or {@code null} in case the annotation is not specified at all
|
|
||||||
*
|
|
||||||
* @throws AssertionFailure in case there is
|
|
||||||
*/
|
|
||||||
private AnnotationInstance getSingleAnnotation(ClassInfo classInfo, DotName annotationName)
|
|
||||||
throws AssertionFailure {
|
|
||||||
List<AnnotationInstance> annotationList = classInfo.annotations().get( annotationName );
|
|
||||||
if ( annotationList == null ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else if ( annotationList.size() == 1 ) {
|
|
||||||
return annotationList.get( 0 );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new AssertionFailure(
|
|
||||||
"There should be only one annotation of type " + annotationName + " defined on" + classInfo.name()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @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.metamodel.source.annotations;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
|
||||||
|
import org.jboss.jandex.AnnotationInstance;
|
||||||
|
import org.jboss.jandex.ClassInfo;
|
||||||
|
import org.jboss.jandex.DotName;
|
||||||
|
|
||||||
|
import org.hibernate.AnnotationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an entity, mapped superclass or component configured via annotations/xml.
|
||||||
|
*
|
||||||
|
* @author Hardy Ferentschik
|
||||||
|
*/
|
||||||
|
public class ConfiguredClass {
|
||||||
|
public static final DotName ENTITY = DotName.createSimple( Entity.class.getName() );
|
||||||
|
public static final DotName HIBERNATE_ENTITY = DotName.createSimple( org.hibernate.annotations.Entity.class.getName() );
|
||||||
|
public static final DotName MAPPED_SUPER_CLASS = DotName.createSimple( MappedSuperclass.class.getName() );
|
||||||
|
|
||||||
|
private final ClassInfo classInfo;
|
||||||
|
private final ConfiguredClassHierarchy hierarchy;
|
||||||
|
|
||||||
|
public ConfiguredClass(ClassInfo info, ConfiguredClassHierarchy hierarchy) {
|
||||||
|
this.classInfo = info;
|
||||||
|
this.hierarchy = hierarchy;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
|
||||||
|
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, ENTITY );
|
||||||
|
AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation( classInfo, MAPPED_SUPER_CLASS );
|
||||||
|
AnnotationInstance hibernateEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, HIBERNATE_ENTITY );
|
||||||
|
|
||||||
|
if ( jpaEntityAnnotation != null && mappedSuperClassAnnotation != null ) {
|
||||||
|
throw new AnnotationException(
|
||||||
|
"An entity cannot be annotated with both @Entity and @MappedSuperclass: "
|
||||||
|
+ classInfo.name().toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassInfo getClassInfo() {
|
||||||
|
return classInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append( "ConfiguredClass" );
|
||||||
|
sb.append( "{classInfo=" ).append( classInfo );
|
||||||
|
sb.append( '}' );
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,16 +23,47 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.source.annotations;
|
package org.hibernate.metamodel.source.annotations;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jboss.jandex.ClassInfo;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AccessType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Hardy Ferentschik
|
* @author Hardy Ferentschik
|
||||||
*/
|
*/
|
||||||
public class EntityHierarchy implements Iterable<Entity> {
|
public class ConfiguredClassHierarchy implements Iterable<ConfiguredClass> {
|
||||||
@Override
|
private final AccessType defaultAccessType;
|
||||||
public Iterator<Entity> iterator() {
|
private final List<ConfiguredClass> configuredClasses;
|
||||||
|
|
||||||
|
ConfiguredClassHierarchy(List<ClassInfo> classes) {
|
||||||
|
configuredClasses = new ArrayList<ConfiguredClass>();
|
||||||
|
for ( ClassInfo info : classes ) {
|
||||||
|
configuredClasses.add( new ConfiguredClass( info, this ) );
|
||||||
|
}
|
||||||
|
defaultAccessType = determineDefaultAccessType();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AccessType determineDefaultAccessType() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<ConfiguredClass> iterator() {
|
||||||
|
return configuredClasses.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append( "ConfiguredClassHierarchy" );
|
||||||
|
sb.append( "{defaultAccessType=" ).append( defaultAccessType );
|
||||||
|
sb.append( ", configuredClasses=" ).append( configuredClasses );
|
||||||
|
sb.append( '}' );
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @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.metamodel.source.annotations;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jboss.jandex.ClassInfo;
|
||||||
|
import org.jboss.jandex.DotName;
|
||||||
|
import org.jboss.jandex.Index;
|
||||||
|
|
||||||
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a annotation index build a list of class hierarchies.
|
||||||
|
*
|
||||||
|
* @author Hardy Ferentschik
|
||||||
|
*/
|
||||||
|
public class ConfiguredClassHierarchyBuilder {
|
||||||
|
|
||||||
|
public Set<ConfiguredClassHierarchy> createEntityHierarchies(Index index) {
|
||||||
|
Map<ClassInfo, List<ClassInfo>> processedClassInfos = new HashMap<ClassInfo, List<ClassInfo>>();
|
||||||
|
|
||||||
|
for ( ClassInfo info : index.getKnownClasses() ) {
|
||||||
|
if ( processedClassInfos.containsKey( info ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<ClassInfo> configuredClassList = new ArrayList<ClassInfo>();
|
||||||
|
ClassInfo tmpClassInfo = info;
|
||||||
|
Class<?> clazz = classForName( tmpClassInfo );
|
||||||
|
while ( clazz != null && !clazz.equals( Object.class ) ) {
|
||||||
|
tmpClassInfo = index.getClassByName( DotName.createSimple( clazz.getName() ) );
|
||||||
|
clazz = clazz.getSuperclass();
|
||||||
|
if ( tmpClassInfo == null ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( existsHierarchyWithClassInfoAsLeaf( processedClassInfos, tmpClassInfo ) ) {
|
||||||
|
List<ClassInfo> classInfoList = processedClassInfos.get( tmpClassInfo );
|
||||||
|
for ( ClassInfo tmpInfo : configuredClassList ) {
|
||||||
|
classInfoList.add( tmpInfo );
|
||||||
|
processedClassInfos.put( tmpInfo, classInfoList );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
configuredClassList.add( 0, tmpClassInfo );
|
||||||
|
processedClassInfos.put( tmpClassInfo, configuredClassList );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<ConfiguredClassHierarchy> hierarchies = new HashSet<ConfiguredClassHierarchy>();
|
||||||
|
List<List<ClassInfo>> processedList = new ArrayList<List<ClassInfo>>();
|
||||||
|
for ( List<ClassInfo> classInfoList : processedClassInfos.values() ) {
|
||||||
|
if ( !processedList.contains( classInfoList ) ) {
|
||||||
|
hierarchies.add( new ConfiguredClassHierarchy( classInfoList ) );
|
||||||
|
processedList.add( classInfoList );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hierarchies;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean existsHierarchyWithClassInfoAsLeaf(Map<ClassInfo, List<ClassInfo>> processedClassInfos, ClassInfo tmpClassInfo) {
|
||||||
|
if ( !processedClassInfos.containsKey( tmpClassInfo ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ClassInfo> classInfoList = processedClassInfos.get( tmpClassInfo );
|
||||||
|
return classInfoList.get( classInfoList.size() - 1 ).equals( tmpClassInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<?> classForName(ClassInfo info) {
|
||||||
|
Class<?> clazz = null;
|
||||||
|
try {
|
||||||
|
clazz = ReflectHelper.classForName( info.toString() );
|
||||||
|
}
|
||||||
|
catch ( ClassNotFoundException e ) {
|
||||||
|
// todo what to do here!?i
|
||||||
|
}
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
|
||||||
* indicated by the @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.metamodel.source.annotations;
|
|
||||||
|
|
||||||
import org.jboss.jandex.ClassInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents an entity or mapped superclass which needs to be mapped.
|
|
||||||
*
|
|
||||||
* @author Hardy Ferentschik
|
|
||||||
*/
|
|
||||||
public class Entity {
|
|
||||||
private ClassInfo classInfo;
|
|
||||||
|
|
||||||
public ClassInfo getClassInfo() {
|
|
||||||
return classInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package org.hibernate.metamodel.source.annotations;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.jboss.jandex.Index;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a annotation index build a list of entity hierarchies.
|
|
||||||
*
|
|
||||||
* @author Hardy Ferentschik
|
|
||||||
*/
|
|
||||||
public class EntityHierarchyBuilder {
|
|
||||||
public List<EntityHierarchy> createEntityHierarchies(Index index) {
|
|
||||||
List<EntityHierarchy> hierarchies = new ArrayList<EntityHierarchy>();
|
|
||||||
|
|
||||||
|
|
||||||
return hierarchies;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package org.hibernate.metamodel.source.annotations;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jboss.jandex.AnnotationInstance;
|
||||||
|
import org.jboss.jandex.ClassInfo;
|
||||||
|
import org.jboss.jandex.DotName;
|
||||||
|
|
||||||
|
import org.hibernate.AssertionFailure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Hardy Ferentschik
|
||||||
|
*/
|
||||||
|
public class JandexHelper {
|
||||||
|
private JandexHelper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param classInfo the class info from which to retrieve the annotation instance
|
||||||
|
* @param annotationName the annotation to retrieve from the class info
|
||||||
|
*
|
||||||
|
* @return the single annotation defined on the class or {@code null} in case the annotation is not specified at all
|
||||||
|
*
|
||||||
|
* @throws org.hibernate.AssertionFailure in case there is
|
||||||
|
*/
|
||||||
|
static public AnnotationInstance getSingleAnnotation(ClassInfo classInfo, DotName annotationName)
|
||||||
|
throws AssertionFailure {
|
||||||
|
List<AnnotationInstance> annotationList = classInfo.annotations().get( annotationName );
|
||||||
|
if ( annotationList == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if ( annotationList.size() == 1 ) {
|
||||||
|
return annotationList.get( 0 );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new AssertionFailure(
|
||||||
|
"There should be only one annotation of type " + annotationName + " defined on" + classInfo.name()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.validation.ValidationException;
|
|
||||||
import javax.xml.bind.JAXBContext;
|
import javax.xml.bind.JAXBContext;
|
||||||
import javax.xml.bind.JAXBElement;
|
import javax.xml.bind.JAXBElement;
|
||||||
import javax.xml.bind.JAXBException;
|
import javax.xml.bind.JAXBException;
|
||||||
|
@ -18,6 +17,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import org.hibernate.AnnotationException;
|
||||||
import org.hibernate.metamodel.source.xml.EntityMappings;
|
import org.hibernate.metamodel.source.xml.EntityMappings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,7 +26,8 @@ import org.hibernate.metamodel.source.xml.EntityMappings;
|
||||||
*/
|
*/
|
||||||
public class OrmXmlParser {
|
public class OrmXmlParser {
|
||||||
private static final Logger log = LoggerFactory.getLogger( OrmXmlParser.class );
|
private static final Logger log = LoggerFactory.getLogger( OrmXmlParser.class );
|
||||||
private static final String ORM_MAPPING_XSD = "org/hibernate/ejb/orm_2_0.xsd";
|
private static final String ORM1_MAPPING_XSD = "org/hibernate/ejb/orm_1_0.xsd";
|
||||||
|
private static final String ORM2_MAPPING_XSD = "org/hibernate/ejb/orm_2_0.xsd";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the given xml configuration files and returns a updated annotation index
|
* Parses the given xml configuration files and returns a updated annotation index
|
||||||
|
@ -40,12 +41,26 @@ public class OrmXmlParser {
|
||||||
|
|
||||||
Set<InputStream> mappingStreams = new HashSet<InputStream>();
|
Set<InputStream> mappingStreams = new HashSet<InputStream>();
|
||||||
for ( String fileName : mappingFileNames ) {
|
for ( String fileName : mappingFileNames ) {
|
||||||
mappingStreams.add( getInputStreamForPath( fileName ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( InputStream in : mappingStreams ) {
|
Schema schema = getMappingSchema( ORM2_MAPPING_XSD );
|
||||||
EntityMappings entityMappings = getEntityMappings( in );
|
InputStream in = getInputStreamForPath( fileName );
|
||||||
// ...
|
EntityMappings entityMappings;
|
||||||
|
try {
|
||||||
|
entityMappings = unmarshallXml( in, schema );
|
||||||
|
}
|
||||||
|
catch ( JAXBException orm2Exception ) {
|
||||||
|
// if we cannot parse against orm_2_0.xsd we try orm_1_0.xsd for backwards compatibility
|
||||||
|
try {
|
||||||
|
schema = getMappingSchema( ORM1_MAPPING_XSD );
|
||||||
|
in = getInputStreamForPath( fileName );
|
||||||
|
entityMappings = unmarshallXml( in, schema );
|
||||||
|
}
|
||||||
|
catch ( JAXBException orm1Exception ) {
|
||||||
|
throw new AnnotationException( "Unable to parse xml configuration.", orm1Exception );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ..
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -62,35 +77,27 @@ public class OrmXmlParser {
|
||||||
return inputStream;
|
return inputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EntityMappings getEntityMappings(InputStream in) {
|
private EntityMappings unmarshallXml(InputStream in, Schema schema) throws JAXBException {
|
||||||
EntityMappings entityMappings;
|
EntityMappings entityMappings;
|
||||||
Schema schema = getMappingSchema();
|
JAXBContext jc = JAXBContext.newInstance( EntityMappings.class );
|
||||||
try {
|
Unmarshaller unmarshaller = jc.createUnmarshaller();
|
||||||
JAXBContext jc = JAXBContext.newInstance( EntityMappings.class );
|
unmarshaller.setSchema( schema );
|
||||||
Unmarshaller unmarshaller = jc.createUnmarshaller();
|
StreamSource stream = new StreamSource( in );
|
||||||
unmarshaller.setSchema( schema );
|
JAXBElement<EntityMappings> root = unmarshaller.unmarshal( stream, EntityMappings.class );
|
||||||
StreamSource stream = new StreamSource( in );
|
entityMappings = root.getValue();
|
||||||
JAXBElement<EntityMappings> root = unmarshaller.unmarshal( stream, EntityMappings.class );
|
|
||||||
entityMappings = root.getValue();
|
|
||||||
}
|
|
||||||
catch ( JAXBException e ) {
|
|
||||||
String msg = "Error parsing mapping file.";
|
|
||||||
log.error( msg );
|
|
||||||
throw new ValidationException( msg, e );
|
|
||||||
}
|
|
||||||
return entityMappings;
|
return entityMappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Schema getMappingSchema() {
|
private Schema getMappingSchema(String schemaVersion) {
|
||||||
ClassLoader loader = OrmXmlParser.class.getClassLoader();
|
ClassLoader loader = OrmXmlParser.class.getClassLoader();
|
||||||
URL schemaUrl = loader.getResource( ORM_MAPPING_XSD );
|
URL schemaUrl = loader.getResource( schemaVersion );
|
||||||
SchemaFactory sf = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI );
|
SchemaFactory sf = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI );
|
||||||
Schema schema = null;
|
Schema schema = null;
|
||||||
try {
|
try {
|
||||||
schema = sf.newSchema( schemaUrl );
|
schema = sf.newSchema( schemaUrl );
|
||||||
}
|
}
|
||||||
catch ( SAXException e ) {
|
catch ( SAXException e ) {
|
||||||
log.debug( "Unable to create schema for {}: {}", ORM_MAPPING_XSD, e.getMessage() );
|
log.debug( "Unable to create schema for {}: {}", ORM2_MAPPING_XSD, e.getMessage() );
|
||||||
}
|
}
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ import static org.junit.Assert.fail;
|
||||||
*/
|
*/
|
||||||
public class BasicAnnotationBindingTests extends AbstractBasicBindingTests {
|
public class BasicAnnotationBindingTests extends AbstractBasicBindingTests {
|
||||||
|
|
||||||
//@FailureExpected(jiraKey = "HHH-5672", message = "Work in progress")
|
@FailureExpected(jiraKey = "HHH-5672", message = "Work in progress")
|
||||||
@Test
|
@Test
|
||||||
public void testSimpleEntityMapping() {
|
public void testSimpleEntityMapping() {
|
||||||
super.testSimpleEntityMapping();
|
super.testSimpleEntityMapping();
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
package org.hibernate.metamodel.source.annotations;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
|
||||||
|
import org.jboss.jandex.ClassInfo;
|
||||||
|
import org.jboss.jandex.DotName;
|
||||||
|
import org.jboss.jandex.Index;
|
||||||
|
import org.jboss.jandex.Indexer;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.AnnotationException;
|
||||||
|
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Hardy Ferentschik
|
||||||
|
*/
|
||||||
|
public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleEntity() {
|
||||||
|
Index index = indexForClass( Foo.class );
|
||||||
|
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
|
||||||
|
Set<ConfiguredClassHierarchy> hierarchies = builder.createEntityHierarchies( index );
|
||||||
|
assertEquals( "There should be only one hierarchy", 1, hierarchies.size() );
|
||||||
|
|
||||||
|
Iterator<ConfiguredClass> iter = hierarchies.iterator().next().iterator();
|
||||||
|
ClassInfo info = iter.next().getClassInfo();
|
||||||
|
assertEquals( "wrong class", DotName.createSimple( Foo.class.getName() ), info.name() );
|
||||||
|
assertFalse( iter.hasNext() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleInheritance() {
|
||||||
|
Index index = indexForClass( B.class, A.class );
|
||||||
|
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
|
||||||
|
Set<ConfiguredClassHierarchy> hierarchies = builder.createEntityHierarchies( index );
|
||||||
|
assertEquals( "There should be only one hierarchy", 1, hierarchies.size() );
|
||||||
|
|
||||||
|
Iterator<ConfiguredClass> iter = hierarchies.iterator().next().iterator();
|
||||||
|
ClassInfo info = iter.next().getClassInfo();
|
||||||
|
assertEquals( "wrong class", DotName.createSimple( A.class.getName() ), info.name() );
|
||||||
|
info = iter.next().getClassInfo();
|
||||||
|
assertEquals( "wrong class", DotName.createSimple( B.class.getName() ), info.name() );
|
||||||
|
assertFalse( iter.hasNext() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleHierarchies() {
|
||||||
|
Index index = indexForClass( B.class, A.class, Foo.class );
|
||||||
|
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
|
||||||
|
Set<ConfiguredClassHierarchy> hierarchies = builder.createEntityHierarchies( index );
|
||||||
|
assertEquals( "There should be only one hierarchy", 2, hierarchies.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMappedSuperClass() {
|
||||||
|
Index index = indexForClass( MappedSubClass.class, MappedSuperClass.class, UnmappedSubClass.class );
|
||||||
|
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
|
||||||
|
Set<ConfiguredClassHierarchy> hierarchies = builder.createEntityHierarchies( index );
|
||||||
|
assertEquals( "There should be only one hierarchy", 1, hierarchies.size() );
|
||||||
|
|
||||||
|
Iterator<ConfiguredClass> iter = hierarchies.iterator().next().iterator();
|
||||||
|
ClassInfo info = iter.next().getClassInfo();
|
||||||
|
assertEquals( "wrong class", DotName.createSimple( MappedSuperClass.class.getName() ), info.name() );
|
||||||
|
info = iter.next().getClassInfo();
|
||||||
|
assertEquals( "wrong class", DotName.createSimple( UnmappedSubClass.class.getName() ), info.name() );
|
||||||
|
assertFalse( iter.hasNext() );
|
||||||
|
info = iter.next().getClassInfo();
|
||||||
|
assertEquals( "wrong class", DotName.createSimple( MappedSubClass.class.getName() ), info.name() );
|
||||||
|
assertFalse( iter.hasNext() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = AnnotationException.class)
|
||||||
|
public void testEntityAndMappedSuperClassAnnotations() {
|
||||||
|
Index index = indexForClass( EntityAndMappedSuperClass.class );
|
||||||
|
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
|
||||||
|
builder.createEntityHierarchies( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Index indexForClass(Class<?>... classes) {
|
||||||
|
Indexer indexer = new Indexer();
|
||||||
|
for ( Class<?> clazz : classes ) {
|
||||||
|
InputStream stream = getClass().getClassLoader().getResourceAsStream(
|
||||||
|
clazz.getName().replace( '.', '/' ) + ".class"
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
indexer.index( stream );
|
||||||
|
}
|
||||||
|
catch ( IOException e ) {
|
||||||
|
fail( "Unable to index" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return indexer.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Foo {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private int id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class A {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private int id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class B extends A {
|
||||||
|
private String name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public class MappedSuperClass {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private int id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UnmappedSubClass extends MappedSuperClass {
|
||||||
|
private String unmappedProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class MappedSubClass extends UnmappedSubClass {
|
||||||
|
private String mappedProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@MappedSuperclass
|
||||||
|
public class EntityAndMappedSuperClass {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,14 @@ public class OrmXmlParserTests extends BaseUnitTestCase {
|
||||||
Set<String> xmlFiles = new HashSet<String>();
|
Set<String> xmlFiles = new HashSet<String>();
|
||||||
xmlFiles.add( "org/hibernate/metamodel/source/annotations/orm.xml" );
|
xmlFiles.add( "org/hibernate/metamodel/source/annotations/orm.xml" );
|
||||||
parser.parseAndUpdateIndex( xmlFiles, null );
|
parser.parseAndUpdateIndex( xmlFiles, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOrmXmlWithOldSchema() {
|
||||||
|
OrmXmlParser parser = new OrmXmlParser();
|
||||||
|
Set<String> xmlFiles = new HashSet<String>();
|
||||||
|
xmlFiles.add( "org/hibernate/metamodel/source/annotations/orm2.xml" );
|
||||||
|
parser.parseAndUpdateIndex( xmlFiles, null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.hibernate.metamodel.source.annotations;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Hardy Ferentschik
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class Star {
|
||||||
|
private int id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
|
||||||
|
version="1.0"
|
||||||
|
>
|
||||||
|
<!-- use orm_1_0 on purpose to test backward compatibility -->
|
||||||
|
<package>org.hibernate.metamodel.source.annotations</package>
|
||||||
|
<entity class="Star" access="FIELD" metadata-complete="false">
|
||||||
|
<attributes>
|
||||||
|
<id name="id">
|
||||||
|
<column name="STAR_ID"/>
|
||||||
|
</id>
|
||||||
|
</attributes>
|
||||||
|
</entity>
|
||||||
|
</entity-mappings>
|
Loading…
Reference in New Issue