package org.hibernate.cfg;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Converts;
import javax.persistence.EmbeddedId;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import org.hibernate.AnnotationException;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.PropertyPath;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.KeyValue;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Table;
public class ComponentPropertyHolder extends AbstractPropertyHolder {
private Component component;
private boolean isOrWithinEmbeddedId;
private boolean isWithinElementCollection;
private String embeddedAttributeName;
private Map<String,AttributeConversionInfo> attributeConversionInfoMap;
public ComponentPropertyHolder(
Component component,
String path,
PropertyData inferredData,
PropertyHolder parent,
MetadataBuildingContext context) {
super( path, parent, inferredData.getPropertyClass(), context );
final XProperty embeddedXProperty = inferredData.getProperty();
setCurrentProperty( embeddedXProperty );
this.component = component;
this.isOrWithinEmbeddedId =
parent.isOrWithinEmbeddedId()
|| ( embeddedXProperty != null &&
( embeddedXProperty.isAnnotationPresent( Id.class )
|| embeddedXProperty.isAnnotationPresent( EmbeddedId.class ) ) );
this.isWithinElementCollection = parent.isWithinElementCollection() ||
parent instanceof CollectionPropertyHolder;
if ( embeddedXProperty != null ) {
this.embeddedAttributeName = embeddedXProperty.getName();
this.attributeConversionInfoMap = processAttributeConversions( embeddedXProperty );
}
else {
this.embeddedAttributeName = "";
this.attributeConversionInfoMap = processAttributeConversions( inferredData.getClassOrElement() );
}
}
private Map<String,AttributeConversionInfo> processAttributeConversions(XProperty embeddedXProperty) {
final Map<String,AttributeConversionInfo> infoMap = new HashMap<String, AttributeConversionInfo>();
final XClass embeddableXClass = embeddedXProperty.getType();
processAttributeConversions( embeddableXClass, infoMap );
{
final Convert convertAnnotation = embeddedXProperty.getAnnotation( Convert.class );
if ( convertAnnotation != null ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
throw new IllegalStateException( "Convert placed on Embedded attribute must define (sub)attributeName" );
}
infoMap.put( info.getAttributeName(), info );
}
}
{
final Converts convertsAnnotation = embeddedXProperty.getAnnotation( Converts.class );
if ( convertsAnnotation != null ) {
for ( Convert convertAnnotation : convertsAnnotation.value() ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
throw new IllegalStateException( "Convert placed on Embedded attribute must define (sub)attributeName" );
}
infoMap.put( info.getAttributeName(), info );
}
}
}
return infoMap;
}
private void processAttributeConversions(XClass embeddableXClass, Map<String, AttributeConversionInfo> infoMap) {
{
final Convert convertAnnotation = embeddableXClass.getAnnotation( Convert.class );
if ( convertAnnotation != null ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
throw new IllegalStateException( "@Convert placed on @Embeddable must define attributeName" );
}
infoMap.put( info.getAttributeName(), info );
}
}
{
final Converts convertsAnnotation = embeddableXClass.getAnnotation( Converts.class );
if ( convertsAnnotation != null ) {
for ( Convert convertAnnotation : convertsAnnotation.value() ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
throw new IllegalStateException( "@Converts placed on @Embeddable must define attributeName" );
}
infoMap.put( info.getAttributeName(), info );
}
}
}
}
private Map<String,AttributeConversionInfo> processAttributeConversions(XClass embeddableXClass) {
final Map<String,AttributeConversionInfo> infoMap = new HashMap<String, AttributeConversionInfo>();
processAttributeConversions( embeddableXClass, infoMap );
return infoMap;
}
@Override
protected String normalizeCompositePath(String attributeName) {
return embeddedAttributeName + '.' + attributeName;
}
@Override
protected String normalizeCompositePathForLogging(String attributeName) {
return normalizeCompositePath( attributeName );
}
@Override
public void startingProperty(XProperty property) {
if ( property == null ) {
return;
}
final String path = embeddedAttributeName + '.' + property.getName();
if ( attributeConversionInfoMap.containsKey( path ) ) {
return;
}
{
final Convert convertAnnotation = property.getAnnotation( Convert.class );
if ( convertAnnotation != null ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, property );
attributeConversionInfoMap.put( property.getName(), info );
}
}
{
final Converts convertsAnnotation = property.getAnnotation( Converts.class );
if ( convertsAnnotation != null ) {
for ( Convert convertAnnotation : convertsAnnotation.value() ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, property );
attributeConversionInfoMap.put( property.getName(), info );
}
}
}
}
@Override
protected AttributeConversionInfo locateAttributeConversionInfo(XProperty property) {
final String propertyName = property.getName();
AttributeConversionInfo conversion = locateAttributeConversionInfo( propertyName );
if ( conversion != null ) {
return conversion;
}
return null;
}
@Override
protected AttributeConversionInfo locateAttributeConversionInfo(String path) {
final String embeddedPath = StringHelper.qualifyConditionally( embeddedAttributeName, path );
AttributeConversionInfo fromParent = parent.locateAttributeConversionInfo( embeddedPath );
if ( fromParent != null ) {
return fromParent;
}
AttributeConversionInfo fromEmbedded = attributeConversionInfoMap.get( embeddedPath );
if ( fromEmbedded != null ) {
return fromEmbedded;
}
return attributeConversionInfoMap.get( path );
}
public String getEntityName() {
return component.getComponentClassName();
}
public void addProperty(Property prop, Ejb3Column[] columns, XClass declaringClass) {
if (columns != null) {
Table table = columns[0].getTable();
if ( !table.equals( component.getTable() ) ) {
if ( component.getPropertySpan() == 0 ) {
component.setTable( table );
}
else {
throw new AnnotationException(
"A component cannot hold properties split into 2 different tables: "
+ this.getPath()
);
}
}
}
addProperty( prop, declaringClass );
}
public Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation) {
return parent.addJoin( joinTableAnn, noDelayInPkColumnCreation );
}
public String getClassName() {
return component.getComponentClassName();
}
public String getEntityOwnerClassName() {
return component.getOwner().getClassName();
}
public Table getTable() {
return component.getTable();
}
public void addProperty(Property prop, XClass declaringClass) {
component.addProperty( prop );
}
public KeyValue getIdentifier() {
return component.getOwner().getIdentifier();
}
public boolean isOrWithinEmbeddedId() {
return isOrWithinEmbeddedId;
}
public boolean isWithinElementCollection() {
return isWithinElementCollection;
}
public PersistentClass getPersistentClass() {
return component.getOwner();
}
public boolean isComponent() {
return true;
}
public boolean isEntity() {
return false;
}
public void setParentProperty(String parentProperty) {
component.setParentProperty( parentProperty );
}
@Override
public Column[] getOverriddenColumn(String propertyName) {
Column[] result = super.getOverriddenColumn( propertyName );
if ( result == null ) {
String userPropertyName = extractUserPropertyName( "id", propertyName );
if ( userPropertyName != null ) result = super.getOverriddenColumn( userPropertyName );
}
if ( result == null ) {
String userPropertyName = extractUserPropertyName( PropertyPath.IDENTIFIER_MAPPER_PROPERTY, propertyName );
if ( userPropertyName != null ) result = super.getOverriddenColumn( userPropertyName );
}
return result;
}
private String (String redundantString, String propertyName) {
String result = null;
String className = component.getOwner().getClassName();
if ( propertyName.startsWith( className )
&& propertyName.length() > className.length() + 2 + redundantString.length()
&& propertyName.substring(
className.length() + 1, className.length() + 1 + redundantString.length()
).equals( redundantString )
) {
result = className + propertyName.substring( className.length() + 1 + redundantString.length() );
}
return result;
}
@Override
public JoinColumn[] getOverriddenJoinColumn(String propertyName) {
return super.getOverriddenJoinColumn( propertyName );
}
@Override
public String toString() {
return super.toString() + "(" + parent.normalizeCompositePathForLogging( embeddedAttributeName ) + ")";
}
}