/* * 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.metamodel; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.IdentifiableType; import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.Type; /** * Defines commonality for the JPA {@link IdentifiableType} types. JPA defines * identifiable types as entities or mapped-superclasses. Basically things to which an * identifier can be attached. * <p/> * NOTE : Currently we only really have support for direct entities in the Hibernate metamodel * as the information for them is consumed into the closest actual entity subclass(es) in the * internal Hibernate mapping-metamodel. * * @author Steve Ebersole */ public abstract class AbstractIdentifiableType<X> extends AbstractManagedType<X> implements IdentifiableType<X>, Serializable { private final boolean hasIdentifierProperty; private final boolean isVersioned; private SingularAttributeImpl<X, ?> id; private SingularAttributeImpl<X, ?> version; private Set<SingularAttribute<? super X,?>> idClassAttributes; public AbstractIdentifiableType( Class<X> javaType, AbstractIdentifiableType<? super X> superType, boolean hasIdentifierProperty, boolean versioned) { super( javaType, superType ); this.hasIdentifierProperty = hasIdentifierProperty; isVersioned = versioned; } /** * {@inheritDoc} */ public AbstractIdentifiableType<? super X> getSupertype() { return ( AbstractIdentifiableType<? super X> ) super.getSupertype(); } /** * Indicates if a non-null super type is required to provide the * identifier attribute(s) if this object does not have a declared * identifier. * . * @return true, if a non-null super type is required to provide * the identifier attribute(s) if this object does not have a * declared identifier; false, otherwise. */ protected abstract boolean requiresSupertypeForNonDeclaredIdentifier(); protected AbstractIdentifiableType<? super X> requireSupertype() { if ( getSupertype() == null ) { throw new IllegalStateException( "No supertype found" ); } return getSupertype(); } /** * {@inheritDoc} */ public boolean hasSingleIdAttribute() { return hasIdentifierProperty; } /** * {@inheritDoc} */ @SuppressWarnings({ "unchecked" }) public <Y> SingularAttribute<? super X, Y> getId(Class<Y> javaType) { final SingularAttribute<? super X, Y> id_; if ( id != null ) { checkSimpleId(); id_ = ( SingularAttribute<? super X, Y> ) id; if ( javaType != id.getJavaType() ) { throw new IllegalArgumentException( "Id attribute was not of specified type : " + javaType.getName() ); } } else { //yuk yuk bad me if ( ! requiresSupertypeForNonDeclaredIdentifier()) { final AbstractIdentifiableType<? super X> supertype = getSupertype(); if (supertype != null) { id_ = supertype.getId( javaType ); } else { id_ = null; } } else { id_ = requireSupertype().getId( javaType ); } } return id_; } /** * Centralized check to ensure the id for this hierarchy is a simple one (i.e., does not use * an id-class). * * @see #checkIdClass() */ protected void checkSimpleId() { if ( ! hasIdentifierProperty ) { throw new IllegalStateException( "This class uses an @IdClass" ); } } /** * {@inheritDoc} */ @SuppressWarnings({ "unchecked" }) public <Y> SingularAttribute<X, Y> getDeclaredId(Class<Y> javaType) { checkDeclaredId(); checkSimpleId(); if ( javaType != id.getJavaType() ) { throw new IllegalArgumentException( "Id attribute was not of specified type : " + javaType.getName() ); } return (SingularAttribute<X, Y>) id; } /** * Centralized check to ensure the id is actually declared on the class mapped here, as opposed to a * super class. */ protected void checkDeclaredId() { if ( id == null ) { throw new IllegalArgumentException( "The id attribute is not declared on this type" ); } } /** * {@inheritDoc} */ public Type<?> getIdType() { if ( id != null ) { checkSimpleId(); return id.getType(); } else { return requireSupertype().getIdType(); } } private boolean hasIdClassAttributesDefined() { return idClassAttributes != null || ( getSupertype() != null && getSupertype().hasIdClassAttributesDefined() ); } /** * {@inheritDoc} */ public Set<SingularAttribute<? super X, ?>> getIdClassAttributes() { if ( idClassAttributes != null ) { checkIdClass(); } else { // Java does not allow casting requireSupertype().getIdClassAttributes() // to Set<SingularAttribute<? super X, ?>> because the // superclass X is a different Java type from this X // (i.e, getSupertype().getJavaType() != getJavaType()). // It will, however, allow a Set<SingularAttribute<? super X, ?>> // to be initialized with requireSupertype().getIdClassAttributes(), // since getSupertype().getJavaType() is a superclass of getJavaType() if ( requiresSupertypeForNonDeclaredIdentifier() ) { idClassAttributes = new HashSet<SingularAttribute<? super X, ?>>( requireSupertype().getIdClassAttributes() ); } else if ( getSupertype() != null && hasIdClassAttributesDefined() ) { idClassAttributes = new HashSet<SingularAttribute<? super X, ?>>( getSupertype().getIdClassAttributes() ); } } return idClassAttributes; } /** * Centralized check to ensure the id for this hierarchy uses an id-class. * * @see #checkSimpleId() */ private void checkIdClass() { if ( hasIdentifierProperty ) { throw new IllegalArgumentException( "This class does not use @IdClass" ); } } /** * {@inheritDoc} */ public boolean hasVersionAttribute() { return isVersioned; } public boolean hasDeclaredVersionAttribute() { return isVersioned && version != null; } /** * {@inheritDoc} */ @SuppressWarnings({ "unchecked" }) public <Y> SingularAttribute<? super X, Y> getVersion(Class<Y> javaType) { if ( ! hasVersionAttribute() ) { return null; } final SingularAttribute<? super X, Y> version_; if ( version != null ) { version_ = ( SingularAttribute<? super X, Y> ) version; if ( javaType != version.getJavaType() ) { throw new IllegalArgumentException( "Version attribute was not of specified type : " + javaType.getName() ); } } else { version_ = requireSupertype().getVersion( javaType ); } return version_; } /** * {@inheritDoc} */ @SuppressWarnings({ "unchecked" }) public <Y> SingularAttribute<X, Y> getDeclaredVersion(Class<Y> javaType) { checkDeclaredVersion(); if ( javaType != version.getJavaType() ) { throw new IllegalArgumentException( "Version attribute was not of specified type : " + javaType.getName() ); } return ( SingularAttribute<X, Y> ) version; } /** * For used to retrieve the declared version when populating the static metamodel. * * @return The declared */ public SingularAttribute<X, ?> 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. */ protected void checkDeclaredVersion() { if ( version == null || ( getSupertype() != null && getSupertype().hasVersionAttribute() )) { throw new IllegalArgumentException( "The version attribute is not declared on this type" ); } } public Builder<X> getBuilder() { final AbstractManagedType.Builder<X> managedBuilder = super.getBuilder(); return new Builder<X>() { public void applyIdAttribute(SingularAttributeImpl<X, ?> idAttribute) { AbstractIdentifiableType.this.id = idAttribute; managedBuilder.addAttribute( idAttribute ); } public void applyIdClassAttributes(Set<SingularAttribute<? super X,?>> idClassAttributes) { for ( SingularAttribute<? super X,?> idClassAttribute : idClassAttributes ) { if ( AbstractIdentifiableType.this == idClassAttribute.getDeclaringType() ) { @SuppressWarnings({ "unchecked" }) SingularAttribute<X,?> declaredAttribute = ( SingularAttribute<X,?> ) idClassAttribute; addAttribute( declaredAttribute ); } } AbstractIdentifiableType.this.idClassAttributes = idClassAttributes; } public void applyVersionAttribute(SingularAttributeImpl<X, ?> versionAttribute) { AbstractIdentifiableType.this.version = versionAttribute; managedBuilder.addAttribute( versionAttribute ); } public void addAttribute(Attribute<X, ?> attribute) { managedBuilder.addAttribute( attribute ); } }; } public static interface Builder<X> extends AbstractManagedType.Builder<X> { public void applyIdAttribute(SingularAttributeImpl<X,?> idAttribute); public void applyIdClassAttributes(Set<SingularAttribute<? super X,?>> idClassAttributes); public void applyVersionAttribute(SingularAttributeImpl<X,?> versionAttribute); } }