PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/projects/hibernate-4.2.0/project/hibernate-entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 483 lines | 334 code | 45 blank | 104 comment | 57 complexity | 451c33c458693b672dec05df81fa40d9 MD5 | raw file
  1. /*
  2. * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
  3. * indicated by the @author tags or express copyright attribution
  4. * statements applied by the authors. All third-party contributions are
  5. * distributed under license by Red Hat Middleware LLC.
  6. *
  7. * This copyrighted material is made available to anyone wishing to use, modify,
  8. * copy, or redistribute it subject to the terms and conditions of the GNU
  9. * Lesser General Public License, as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  13. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  14. * for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this distribution; if not, write to:
  18. * Free Software Foundation, Inc.
  19. * 51 Franklin Street, Fifth Floor
  20. * Boston, MA 02110-1301 USA
  21. */
  22. package org.hibernate.ejb.metamodel;
  23. import java.lang.reflect.Field;
  24. import java.util.ArrayList;
  25. import java.util.Collections;
  26. import java.util.HashMap;
  27. import java.util.HashSet;
  28. import java.util.Iterator;
  29. import java.util.List;
  30. import java.util.Map;
  31. import java.util.Set;
  32. import javax.persistence.metamodel.Attribute;
  33. import javax.persistence.metamodel.IdentifiableType;
  34. import javax.persistence.metamodel.MappedSuperclassType;
  35. import javax.persistence.metamodel.SingularAttribute;
  36. import org.jboss.logging.Logger;
  37. import org.hibernate.annotations.common.AssertionFailure;
  38. import org.hibernate.ejb.internal.EntityManagerMessageLogger;
  39. import org.hibernate.engine.spi.SessionFactoryImplementor;
  40. import org.hibernate.internal.util.collections.CollectionHelper;
  41. import org.hibernate.mapping.Component;
  42. import org.hibernate.mapping.KeyValue;
  43. import org.hibernate.mapping.MappedSuperclass;
  44. import org.hibernate.mapping.PersistentClass;
  45. import org.hibernate.mapping.Property;
  46. /**
  47. * Defines a context for storing information during the building of the {@link MetamodelImpl}.
  48. * <p/>
  49. * This contextual information includes data needing to be processed in a second pass as well as
  50. * cross-references into the built metamodel classes.
  51. * <p/>
  52. * At the end of the day, clients are interested in the {@link #getEntityTypeMap} and {@link #getEmbeddableTypeMap}
  53. * results, which represent all the registered {@linkplain #registerEntityType entities} and
  54. * {@linkplain #registerEmbeddedableType embeddables} respectively.
  55. *
  56. * @author Steve Ebersole
  57. * @author Emmanuel Bernard
  58. */
  59. class MetadataContext {
  60. private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
  61. MetadataContext.class.getName());
  62. private final SessionFactoryImplementor sessionFactory;
  63. private final boolean ignoreUnsupported;
  64. private final AttributeFactory attributeFactory = new AttributeFactory( this );
  65. private Map<Class<?>,EntityTypeImpl<?>> entityTypes
  66. = new HashMap<Class<?>, EntityTypeImpl<?>>();
  67. private Map<String,EntityTypeImpl<?>> entityTypesByEntityName
  68. = new HashMap<String, EntityTypeImpl<?>>();
  69. private Map<PersistentClass,EntityTypeImpl<?>> entityTypesByPersistentClass
  70. = new HashMap<PersistentClass,EntityTypeImpl<?>>();
  71. private Map<Class<?>, EmbeddableTypeImpl<?>> embeddables
  72. = new HashMap<Class<?>, EmbeddableTypeImpl<?>>();
  73. private Map<MappedSuperclass, MappedSuperclassTypeImpl<?>> mappedSuperclassByMappedSuperclassMapping
  74. = new HashMap<MappedSuperclass,MappedSuperclassTypeImpl<?>>();
  75. //this list contains MappedSuperclass and EntityTypes ordered by superclass first
  76. private List<Object> orderedMappings = new ArrayList<Object>();
  77. /**
  78. * Stack of PersistentClass being process. Last in the list is the highest in the stack.
  79. *
  80. */
  81. private List<PersistentClass> stackOfPersistentClassesBeingProcessed
  82. = new ArrayList<PersistentClass>();
  83. private Map<MappedSuperclassTypeImpl<?>, PersistentClass> mappedSuperClassTypeToPersistentClass
  84. = new HashMap<MappedSuperclassTypeImpl<?>, PersistentClass>();
  85. public MetadataContext(SessionFactoryImplementor sessionFactory, boolean ignoreUnsupported) {
  86. this.sessionFactory = sessionFactory;
  87. this.ignoreUnsupported = ignoreUnsupported;
  88. }
  89. /*package*/ SessionFactoryImplementor getSessionFactory() {
  90. return sessionFactory;
  91. }
  92. /*package*/ boolean isIgnoreUnsupported() {
  93. return ignoreUnsupported;
  94. }
  95. /**
  96. * Retrieves the {@linkplain Class java type} to {@link EntityTypeImpl} map.
  97. *
  98. * @return The {@linkplain Class java type} to {@link EntityTypeImpl} map.
  99. */
  100. public Map<Class<?>, EntityTypeImpl<?>> getEntityTypeMap() {
  101. return Collections.unmodifiableMap( entityTypes );
  102. }
  103. public Map<Class<?>, EmbeddableTypeImpl<?>> getEmbeddableTypeMap() {
  104. return Collections.unmodifiableMap( embeddables );
  105. }
  106. public Map<Class<?>,MappedSuperclassType<?>> getMappedSuperclassTypeMap() {
  107. // we need to actually build this map...
  108. final Map<Class<?>,MappedSuperclassType<?>> mappedSuperClassTypeMap = CollectionHelper.mapOfSize(
  109. mappedSuperclassByMappedSuperclassMapping.size()
  110. );
  111. for ( MappedSuperclassTypeImpl mappedSuperclassType : mappedSuperclassByMappedSuperclassMapping.values() ) {
  112. mappedSuperClassTypeMap.put(
  113. mappedSuperclassType.getJavaType(),
  114. mappedSuperclassType
  115. );
  116. }
  117. return mappedSuperClassTypeMap;
  118. }
  119. /*package*/ void registerEntityType(PersistentClass persistentClass, EntityTypeImpl<?> entityType) {
  120. entityTypes.put( entityType.getBindableJavaType(), entityType );
  121. entityTypesByEntityName.put( persistentClass.getEntityName(), entityType );
  122. entityTypesByPersistentClass.put( persistentClass, entityType );
  123. orderedMappings.add( persistentClass );
  124. }
  125. /*package*/ void registerEmbeddedableType(EmbeddableTypeImpl<?> embeddableType) {
  126. embeddables.put( embeddableType.getJavaType(), embeddableType );
  127. }
  128. /*package*/ void registerMappedSuperclassType(MappedSuperclass mappedSuperclass,
  129. MappedSuperclassTypeImpl<?> mappedSuperclassType) {
  130. mappedSuperclassByMappedSuperclassMapping.put( mappedSuperclass, mappedSuperclassType );
  131. orderedMappings.add( mappedSuperclass );
  132. mappedSuperClassTypeToPersistentClass.put( mappedSuperclassType, getEntityWorkedOn() );
  133. }
  134. /**
  135. * Given a Hibernate {@link PersistentClass}, locate the corresponding JPA {@link org.hibernate.type.EntityType}
  136. * implementation. May retur null if the given {@link PersistentClass} has not yet been processed.
  137. *
  138. * @param persistentClass The Hibernate (config time) metamodel instance representing an entity.
  139. * @return Tne corresponding JPA {@link org.hibernate.type.EntityType}, or null if not yet processed.
  140. */
  141. public EntityTypeImpl<?> locateEntityType(PersistentClass persistentClass) {
  142. return entityTypesByPersistentClass.get( persistentClass );
  143. }
  144. /**
  145. * Given a Java {@link Class}, locate the corresponding JPA {@link org.hibernate.type.EntityType}. May
  146. * return null which could means that no such mapping exists at least at this time.
  147. *
  148. * @param javaType The java class.
  149. * @return The corresponding JPA {@link org.hibernate.type.EntityType}, or null.
  150. */
  151. public EntityTypeImpl<?> locateEntityType(Class<?> javaType) {
  152. return entityTypes.get( javaType );
  153. }
  154. /**
  155. * Given an entity-name, locate the corresponding JPA {@link org.hibernate.type.EntityType}. May
  156. * return null which could means that no such mapping exists at least at this time.
  157. *
  158. * @param entityName The entity-name.
  159. * @return The corresponding JPA {@link org.hibernate.type.EntityType}, or null.
  160. */
  161. public EntityTypeImpl<?> locateEntityType(String entityName) {
  162. return entityTypesByEntityName.get( entityName );
  163. }
  164. @SuppressWarnings({ "unchecked" })
  165. public void wrapUp() {
  166. LOG.trace("Wrapping up metadata context...");
  167. //we need to process types from superclasses to subclasses
  168. for (Object mapping : orderedMappings) {
  169. if ( PersistentClass.class.isAssignableFrom( mapping.getClass() ) ) {
  170. @SuppressWarnings( "unchecked" )
  171. final PersistentClass safeMapping = (PersistentClass) mapping;
  172. LOG.trace("Starting entity [" + safeMapping.getEntityName() + "]");
  173. try {
  174. final EntityTypeImpl<?> jpa2Mapping = entityTypesByPersistentClass.get( safeMapping );
  175. applyIdMetadata( safeMapping, jpa2Mapping );
  176. applyVersionAttribute( safeMapping, jpa2Mapping );
  177. Iterator<Property> properties = safeMapping.getDeclaredPropertyIterator();
  178. while ( properties.hasNext() ) {
  179. final Property property = properties.next();
  180. if ( property.getValue() == safeMapping.getIdentifierMapper() ) {
  181. // property represents special handling for id-class mappings but we have already
  182. // accounted for the embedded property mappings in #applyIdMetadata &&
  183. // #buildIdClassAttributes
  184. continue;
  185. }
  186. if ( safeMapping.isVersioned() && property == safeMapping.getVersion() ) {
  187. // skip the version property, it was already handled previously.
  188. continue;
  189. }
  190. final Attribute attribute = attributeFactory.buildAttribute( jpa2Mapping, property );
  191. if ( attribute != null ) {
  192. jpa2Mapping.getBuilder().addAttribute( attribute );
  193. }
  194. }
  195. jpa2Mapping.lock();
  196. populateStaticMetamodel( jpa2Mapping );
  197. }
  198. finally {
  199. LOG.trace("Completed entity [" + safeMapping.getEntityName() + "]");
  200. }
  201. }
  202. else if ( MappedSuperclass.class.isAssignableFrom( mapping.getClass() ) ) {
  203. @SuppressWarnings( "unchecked" )
  204. final MappedSuperclass safeMapping = (MappedSuperclass) mapping;
  205. LOG.trace("Starting mapped superclass [" + safeMapping.getMappedClass().getName() + "]");
  206. try {
  207. final MappedSuperclassTypeImpl<?> jpa2Mapping = mappedSuperclassByMappedSuperclassMapping.get(
  208. safeMapping
  209. );
  210. applyIdMetadata( safeMapping, jpa2Mapping );
  211. applyVersionAttribute( safeMapping, jpa2Mapping );
  212. Iterator<Property> properties = safeMapping.getDeclaredPropertyIterator();
  213. while ( properties.hasNext() ) {
  214. final Property property = properties.next();
  215. if ( safeMapping.isVersioned() && property == safeMapping.getVersion() ) {
  216. // skip the version property, it was already handled previously.
  217. continue;
  218. }
  219. final Attribute attribute = attributeFactory.buildAttribute( jpa2Mapping, property );
  220. if ( attribute != null ) {
  221. jpa2Mapping.getBuilder().addAttribute( attribute );
  222. }
  223. }
  224. jpa2Mapping.lock();
  225. populateStaticMetamodel( jpa2Mapping );
  226. }
  227. finally {
  228. LOG.trace("Completed mapped superclass [" + safeMapping.getMappedClass().getName() + "]");
  229. }
  230. }
  231. else {
  232. throw new AssertionFailure( "Unexpected mapping type: " + mapping.getClass() );
  233. }
  234. }
  235. for ( EmbeddableTypeImpl embeddable : embeddables.values() ) {
  236. populateStaticMetamodel( embeddable );
  237. }
  238. }
  239. private <X> void applyIdMetadata(PersistentClass persistentClass, EntityTypeImpl<X> jpaEntityType) {
  240. if ( persistentClass.hasIdentifierProperty() ) {
  241. final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty();
  242. if (declaredIdentifierProperty != null) {
  243. jpaEntityType.getBuilder().applyIdAttribute(
  244. attributeFactory.buildIdAttribute( jpaEntityType, declaredIdentifierProperty )
  245. );
  246. }
  247. }
  248. else if ( persistentClass.hasIdentifierMapper() ) {
  249. @SuppressWarnings( "unchecked")
  250. Iterator<Property> propertyIterator = persistentClass.getIdentifierMapper().getPropertyIterator();
  251. Set<SingularAttribute<? super X, ?>> attributes = buildIdClassAttributes( jpaEntityType, propertyIterator );
  252. jpaEntityType.getBuilder().applyIdClassAttributes( attributes );
  253. }
  254. else {
  255. final KeyValue value = persistentClass.getIdentifier();
  256. if (value instanceof Component ) {
  257. final Component component = ( Component ) value;
  258. if ( component.getPropertySpan() > 1 ) {
  259. //FIXME we are an Hibernate embedded id (ie not type)
  260. }
  261. else {
  262. //FIXME take care of declared vs non declared property
  263. jpaEntityType.getBuilder().applyIdAttribute(
  264. attributeFactory.buildIdAttribute(
  265. jpaEntityType,
  266. (Property) component.getPropertyIterator().next() )
  267. );
  268. }
  269. }
  270. }
  271. }
  272. private <X> void applyIdMetadata(MappedSuperclass mappingType, MappedSuperclassTypeImpl<X> jpaMappingType) {
  273. if ( mappingType.hasIdentifierProperty() ) {
  274. final Property declaredIdentifierProperty = mappingType.getDeclaredIdentifierProperty();
  275. if (declaredIdentifierProperty != null) {
  276. jpaMappingType.getBuilder().applyIdAttribute(
  277. attributeFactory.buildIdAttribute( jpaMappingType, declaredIdentifierProperty )
  278. );
  279. }
  280. }
  281. //an MappedSuperclass can have no identifier if the id is set below in the hierarchy
  282. else if ( mappingType.getIdentifierMapper() != null ){
  283. @SuppressWarnings( "unchecked")
  284. Iterator<Property> propertyIterator = mappingType.getIdentifierMapper().getPropertyIterator();
  285. Set<SingularAttribute<? super X, ?>> attributes = buildIdClassAttributes( jpaMappingType, propertyIterator );
  286. jpaMappingType.getBuilder().applyIdClassAttributes( attributes );
  287. }
  288. }
  289. private <X> void applyVersionAttribute(PersistentClass persistentClass, EntityTypeImpl<X> jpaEntityType) {
  290. final Property declaredVersion = persistentClass.getDeclaredVersion();
  291. if (declaredVersion != null) {
  292. jpaEntityType.getBuilder().applyVersionAttribute(
  293. attributeFactory.buildVersionAttribute( jpaEntityType, declaredVersion )
  294. );
  295. }
  296. }
  297. private <X> void applyVersionAttribute(MappedSuperclass mappingType, MappedSuperclassTypeImpl<X> jpaMappingType) {
  298. final Property declaredVersion = mappingType.getDeclaredVersion();
  299. if ( declaredVersion != null ) {
  300. jpaMappingType.getBuilder().applyVersionAttribute(
  301. attributeFactory.buildVersionAttribute( jpaMappingType, declaredVersion )
  302. );
  303. }
  304. }
  305. private <X> Set<SingularAttribute<? super X, ?>> buildIdClassAttributes(
  306. AbstractIdentifiableType<X> ownerType,
  307. Iterator<Property> propertyIterator) {
  308. LOG.trace("Building old-school composite identifier [" + ownerType.getJavaType().getName() + "]");
  309. Set<SingularAttribute<? super X, ?>> attributes = new HashSet<SingularAttribute<? super X, ?>>();
  310. while ( propertyIterator.hasNext() ) {
  311. attributes.add( attributeFactory.buildIdAttribute( ownerType, propertyIterator.next() ) );
  312. }
  313. return attributes;
  314. }
  315. private <X> void populateStaticMetamodel(AbstractManagedType<X> managedType) {
  316. final Class<X> managedTypeClass = managedType.getJavaType();
  317. final String metamodelClassName = managedTypeClass.getName() + "_";
  318. try {
  319. final Class metamodelClass = Class.forName( metamodelClassName, true, managedTypeClass.getClassLoader() );
  320. // we found the class; so populate it...
  321. registerAttributes( metamodelClass, managedType );
  322. }
  323. catch ( ClassNotFoundException ignore ) {
  324. // nothing to do...
  325. }
  326. // todo : this does not account for @MappeSuperclass, mainly because this is not being tracked in our
  327. // internal metamodel as populated from the annotatios properly
  328. AbstractManagedType<? super X> superType = managedType.getSupertype();
  329. if ( superType != null ) {
  330. populateStaticMetamodel( superType );
  331. }
  332. }
  333. private final Set<Class> processedMetamodelClasses = new HashSet<Class>();
  334. private <X> void registerAttributes(Class metamodelClass, AbstractManagedType<X> managedType) {
  335. if ( ! processedMetamodelClasses.add( metamodelClass ) ) {
  336. return;
  337. }
  338. // push the attributes on to the metamodel class...
  339. for ( Attribute<X, ?> attribute : managedType.getDeclaredAttributes() ) {
  340. registerAttribute( metamodelClass, attribute );
  341. }
  342. if ( IdentifiableType.class.isInstance( managedType ) ) {
  343. final AbstractIdentifiableType<X> entityType = ( AbstractIdentifiableType<X> ) managedType;
  344. // handle version
  345. if ( entityType.hasDeclaredVersionAttribute() ) {
  346. registerAttribute( metamodelClass, entityType.getDeclaredVersion() );
  347. }
  348. // handle id-class mappings specially
  349. if ( ! entityType.hasSingleIdAttribute() ) {
  350. final Set<SingularAttribute<? super X, ?>> attributes = entityType.getIdClassAttributes();
  351. if ( attributes != null ) {
  352. for ( SingularAttribute<? super X, ?> attribute : attributes ) {
  353. registerAttribute( metamodelClass, attribute );
  354. }
  355. }
  356. }
  357. }
  358. }
  359. private <X> void registerAttribute(Class metamodelClass, Attribute<X, ?> attribute) {
  360. final String name = attribute.getName();
  361. try {
  362. // there is a shortcoming in the existing Hibernate code in terms of the way MappedSuperclass
  363. // support was bolted on which comes to bear right here when the attribute is an embeddable type
  364. // defined on a MappedSuperclass. We do not have the correct information to determine the
  365. // appropriate attribute declarer in such cases and so the incoming metamodelClass most likely
  366. // does not represent the declarer in such cases.
  367. //
  368. // As a result, in the case of embeddable classes we simply use getField rather than get
  369. // getDeclaredField
  370. final Field field = attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED
  371. ? metamodelClass.getField( name )
  372. : metamodelClass.getDeclaredField( name );
  373. try {
  374. if ( ! field.isAccessible() ) {
  375. // should be public anyway, but to be sure...
  376. field.setAccessible( true );
  377. }
  378. field.set( null, attribute );
  379. }
  380. catch ( IllegalAccessException e ) {
  381. // todo : exception type?
  382. throw new AssertionFailure(
  383. "Unable to inject static metamodel attribute : " + metamodelClass.getName() + '#' + name,
  384. e
  385. );
  386. }
  387. catch ( IllegalArgumentException e ) {
  388. // most likely a mismatch in the type we are injecting and the defined field; this represents a
  389. // mismatch in how the annotation processor interpretted the attribute and how our metamodel
  390. // and/or annotation binder did.
  391. // This is particularly the case as arrays are nto handled propery by the StaticMetamodel generator
  392. // throw new AssertionFailure(
  393. // "Illegal argument on static metamodel field injection : " + metamodelClass.getName() + '#' + name
  394. // + "; expected type : " + attribute.getClass().getName()
  395. // + "; encountered type : " + field.getType().getName()
  396. // );
  397. LOG.illegalArgumentOnStaticMetamodelFieldInjection(metamodelClass.getName(),
  398. name,
  399. attribute.getClass().getName(),
  400. field.getType().getName());
  401. }
  402. }
  403. catch ( NoSuchFieldException e ) {
  404. LOG.unableToLocateStaticMetamodelField(metamodelClass.getName(), name);
  405. // throw new AssertionFailure(
  406. // "Unable to locate static metamodel field : " + metamodelClass.getName() + '#' + name
  407. // );
  408. }
  409. }
  410. public MappedSuperclassTypeImpl<?> locateMappedSuperclassType(MappedSuperclass mappedSuperclass) {
  411. return mappedSuperclassByMappedSuperclassMapping.get(mappedSuperclass);
  412. }
  413. public void pushEntityWorkedOn(PersistentClass persistentClass) {
  414. stackOfPersistentClassesBeingProcessed.add(persistentClass);
  415. }
  416. public void popEntityWorkedOn(PersistentClass persistentClass) {
  417. final PersistentClass stackTop = stackOfPersistentClassesBeingProcessed.remove(
  418. stackOfPersistentClassesBeingProcessed.size() - 1
  419. );
  420. if (stackTop != persistentClass) {
  421. throw new AssertionFailure( "Inconsistent popping: "
  422. + persistentClass.getEntityName() + " instead of " + stackTop.getEntityName() );
  423. }
  424. }
  425. private PersistentClass getEntityWorkedOn() {
  426. return stackOfPersistentClassesBeingProcessed.get(
  427. stackOfPersistentClassesBeingProcessed.size() - 1
  428. );
  429. }
  430. public PersistentClass getPersistentClassHostingProperties(MappedSuperclassTypeImpl<?> mappedSuperclassType) {
  431. final PersistentClass persistentClass = mappedSuperClassTypeToPersistentClass.get( mappedSuperclassType );
  432. if (persistentClass == null) {
  433. throw new AssertionFailure( "Could not find PersistentClass for MappedSuperclassType: "
  434. + mappedSuperclassType.getJavaType() );
  435. }
  436. return persistentClass;
  437. }
  438. }