org.hibernate.metamodel.internal.AbstractIdentifiableType Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-core Show documentation
Show all versions of hibernate-core Show documentation
Hibernate's core ORM functionality
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.metamodel.internal;
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.
*
* 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
extends AbstractManagedType
implements IdentifiableType, Serializable {
private final boolean hasIdentifierProperty;
private final boolean hasIdClass;
private SingularAttributeImpl id;
private Set> idClassAttributes;
private final boolean isVersioned;
private SingularAttributeImpl version;
public AbstractIdentifiableType(
Class javaType,
String typeName,
AbstractIdentifiableType superType,
boolean hasIdClass,
boolean hasIdentifierProperty,
boolean versioned) {
super( javaType, typeName, superType );
this.hasIdClass = hasIdClass;
this.hasIdentifierProperty = hasIdentifierProperty;
this.isVersioned = versioned;
}
public boolean hasIdClass() {
return hasIdClass;
}
@Override
public boolean hasSingleIdAttribute() {
return !hasIdClass() && hasIdentifierProperty;
}
@Override
@SuppressWarnings("unchecked")
public AbstractIdentifiableType getSupertype() {
// overridden simply to perform the cast
return (AbstractIdentifiableType) super.getSupertype();
}
@Override
@SuppressWarnings({ "unchecked" })
public SingularAttribute getId(Class javaType) {
ensureNoIdClass();
SingularAttributeImpl id = locateIdAttribute();
if ( id != null ) {
checkType( id, javaType );
}
return ( SingularAttribute ) id;
}
private void ensureNoIdClass() {
if ( hasIdClass() ) {
throw new IllegalArgumentException(
"Illegal call to IdentifiableType#getId for class [" + getTypeName() + "] defined with @IdClass"
);
}
}
private SingularAttributeImpl locateIdAttribute() {
if ( id != null ) {
return id;
}
else {
if ( getSupertype() != null ) {
SingularAttributeImpl id = getSupertype().internalGetId();
if ( id != null ) {
return id;
}
}
}
return null;
}
protected SingularAttributeImpl internalGetId() {
if ( id != null ) {
return id;
}
else {
if ( getSupertype() != null ) {
return getSupertype().internalGetId();
}
}
return null;
}
@SuppressWarnings("unchecked")
private void checkType(SingularAttributeImpl attribute, Class javaType) {
if ( ! javaType.isAssignableFrom( attribute.getType().getJavaType() ) ) {
throw new IllegalArgumentException(
String.format(
"Attribute [%s#%s : %s] not castable to requested type [%s]",
getTypeName(),
attribute.getName(),
attribute.getType().getJavaType().getName(),
javaType.getName()
)
);
}
}
@Override
@SuppressWarnings({ "unchecked" })
public SingularAttribute getDeclaredId(Class javaType) {
ensureNoIdClass();
if ( id == null ) {
throw new IllegalArgumentException( "The id attribute is not declared on this type [" + getTypeName() + "]" );
}
checkType( id, javaType );
return (SingularAttribute) id;
}
@Override
@SuppressWarnings("unchecked")
public Type getIdType() {
final SingularAttributeImpl id = locateIdAttribute();
if ( id != null ) {
return id.getType();
}
Set> idClassAttributes = getIdClassAttributesSafely();
if ( idClassAttributes != null ) {
if ( idClassAttributes.size() == 1 ) {
return idClassAttributes.iterator().next().getType();
}
}
return null;
}
/**
* A form of {@link #getIdClassAttributes} which prefers to return {@code null} rather than throw exceptions
*
* @return IdClass attributes or {@code null}
*/
public Set> getIdClassAttributesSafely() {
if ( !hasIdClass() ) {
return null;
}
final Set> attributes = new HashSet>();
internalCollectIdClassAttributes( attributes );
if ( attributes.isEmpty() ) {
return null;
}
return attributes;
}
@Override
public Set> getIdClassAttributes() {
if ( !hasIdClass() ) {
throw new IllegalArgumentException( "This class [" + getJavaType() + "] does not define an IdClass" );
}
final Set> attributes = new HashSet>();
internalCollectIdClassAttributes( attributes );
if ( attributes.isEmpty() ) {
throw new IllegalArgumentException( "Unable to locate IdClass attributes [" + getJavaType() + "]" );
}
return attributes;
}
@SuppressWarnings("unchecked")
private void internalCollectIdClassAttributes(Set attributes) {
if ( idClassAttributes != null ) {
attributes.addAll( idClassAttributes );
}
else if ( getSupertype() != null ) {
getSupertype().internalCollectIdClassAttributes( attributes );
}
}
@Override
public boolean hasVersionAttribute() {
return isVersioned;
}
public boolean hasDeclaredVersionAttribute() {
return isVersioned && version != null;
}
@Override
@SuppressWarnings({ "unchecked" })
public SingularAttribute getVersion(Class javaType) {
// todo : is return null allowed?
if ( ! hasVersionAttribute() ) {
return null;
}
SingularAttributeImpl version = locateVersionAttribute();
if ( version != null ) {
checkType( version, javaType );
}
return ( SingularAttribute ) version;
}
private SingularAttributeImpl locateVersionAttribute() {
if ( version != null ) {
return version;
}
else {
if ( getSupertype() != null ) {
SingularAttributeImpl version = getSupertype().internalGetVersion();
if ( version != null ) {
return version;
}
}
}
return null;
}
protected SingularAttributeImpl internalGetVersion() {
if ( version != null ) {
return version;
}
else {
if ( getSupertype() != null ) {
return getSupertype().internalGetVersion();
}
}
return null;
}
@Override
@SuppressWarnings({ "unchecked" })
public SingularAttribute getDeclaredVersion(Class javaType) {
checkDeclaredVersion();
checkType( version, javaType );
return ( SingularAttribute ) version;
}
private void checkDeclaredVersion() {
if ( version == null || ( getSupertype() != null && getSupertype().hasVersionAttribute() )) {
throw new IllegalArgumentException(
"The version attribute is not declared by this type [" + getJavaType() + "]"
);
}
}
/**
* For used to retrieve the declared version when populating the static metamodel.
*
* @return The declared
*/
public SingularAttribute getDeclaredVersion() {
checkDeclaredVersion();
return version;
}
public Builder getBuilder() {
final AbstractManagedType.Builder managedBuilder = super.getBuilder();
return new Builder() {
public void applyIdAttribute(SingularAttributeImpl idAttribute) {
AbstractIdentifiableType.this.id = idAttribute;
managedBuilder.addAttribute( idAttribute );
}
public void applyIdClassAttributes(Set> idClassAttributes) {
for ( SingularAttribute idClassAttribute : idClassAttributes ) {
if ( AbstractIdentifiableType.this == idClassAttribute.getDeclaringType() ) {
@SuppressWarnings({ "unchecked" })
SingularAttribute declaredAttribute = ( SingularAttribute ) idClassAttribute;
addAttribute( declaredAttribute );
}
}
AbstractIdentifiableType.this.idClassAttributes = idClassAttributes;
}
public void applyVersionAttribute(SingularAttributeImpl versionAttribute) {
AbstractIdentifiableType.this.version = versionAttribute;
managedBuilder.addAttribute( versionAttribute );
}
public void addAttribute(Attribute attribute) {
managedBuilder.addAttribute( attribute );
}
};
}
public static interface Builder extends AbstractManagedType.Builder {
public void applyIdAttribute(SingularAttributeImpl idAttribute);
public void applyIdClassAttributes(Set> idClassAttributes);
public void applyVersionAttribute(SingularAttributeImpl versionAttribute);
}
}