Author: epbernard Date: 2006-04-18 22:24:45 -0400 (Tue, 18 Apr 2006) New Revision: 9766 Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/reflection/java/EJB3OverridenAnnotationReader.java trunk/HibernateExt/metadata/src/java/org/hibernate/reflection/java/xml/XMLContext.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/EJB3OverridenAnnotationReaderTest.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/TennisMatch.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/orm.xml Log: Support xml overriding for attribute and association overriding Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/reflection/java/EJB3OverridenAnnotationReader.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/reflection/java/EJB3OverridenAnnotationReader.java 2006-04-19 01:45:07 UTC (rev 9765) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/reflection/java/EJB3OverridenAnnotationReader.java 2006-04-19 02:24:45 UTC (rev 9766) @@ -10,45 +10,52 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import javax.persistence.AssociationOverride; +import javax.persistence.AssociationOverrides; +import javax.persistence.AttributeOverride; +import javax.persistence.AttributeOverrides; +import javax.persistence.Column; +import javax.persistence.ColumnResult; +import javax.persistence.DiscriminatorColumn; +import javax.persistence.DiscriminatorType; +import javax.persistence.DiscriminatorValue; import javax.persistence.Embeddable; import javax.persistence.Entity; +import javax.persistence.EntityResult; +import javax.persistence.ExcludeDefaultListeners; +import javax.persistence.ExcludeSuperclassListeners; +import javax.persistence.FieldResult; +import javax.persistence.IdClass; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.JoinColumn; import javax.persistence.MappedSuperclass; +import javax.persistence.NamedNativeQueries; +import javax.persistence.NamedNativeQuery; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.PrimaryKeyJoinColumns; +import javax.persistence.QueryHint; import javax.persistence.SecondaryTable; import javax.persistence.SecondaryTables; +import javax.persistence.SequenceGenerator; +import javax.persistence.SqlResultSetMapping; +import javax.persistence.SqlResultSetMappings; import javax.persistence.Table; -import javax.persistence.PrimaryKeyJoinColumns; -import javax.persistence.IdClass; -import javax.persistence.Inheritance; -import javax.persistence.DiscriminatorValue; -import javax.persistence.DiscriminatorColumn; -import javax.persistence.SequenceGenerator; import javax.persistence.TableGenerator; -import javax.persistence.NamedQuery; -import javax.persistence.NamedQueries; -import javax.persistence.QueryHint; -import javax.persistence.DiscriminatorType; -import javax.persistence.InheritanceType; import javax.persistence.UniqueConstraint; -import javax.persistence.NamedNativeQuery; -import javax.persistence.NamedNativeQueries; -import javax.persistence.SqlResultSetMapping; -import javax.persistence.SqlResultSetMappings; -import javax.persistence.EntityResult; -import javax.persistence.FieldResult; -import javax.persistence.ColumnResult; -import javax.persistence.ExcludeDefaultListeners; -import javax.persistence.ExcludeSuperclassListeners; +import org.dom4j.Attribute; import org.dom4j.Element; -import org.dom4j.Attribute; +import org.hibernate.AnnotationException; import org.hibernate.annotationfactory.AnnotationDescriptor; import org.hibernate.annotationfactory.AnnotationFactory; +import org.hibernate.annotations.AccessType; import org.hibernate.reflection.Filter; import org.hibernate.reflection.java.xml.XMLContext; -import org.hibernate.AnnotationException; +import org.hibernate.util.ReflectHelper; import org.hibernate.util.StringHelper; -import org.hibernate.util.ReflectHelper; /** * Encapsulates the overriding of Java annotations from an EJB 3.0 descriptor. @@ -94,11 +101,17 @@ annotationToXml.put( SqlResultSetMappings.class, "sql-result-set-mapping" ); annotationToXml.put( ExcludeDefaultListeners.class, "exclude-default-listeners" ); annotationToXml.put( ExcludeSuperclassListeners.class, "exclude-superclass-listeners" ); + annotationToXml.put( AccessType.class, "access" ); + annotationToXml.put( AttributeOverride.class, "attribute-override" ); + annotationToXml.put( AttributeOverrides.class, "attribute-override" ); + annotationToXml.put( AttributeOverride.class, "association-override" ); + annotationToXml.put( AttributeOverrides.class, "association-override" ); } private XMLContext xmlContext; private String className; private String propertyName; + private boolean isField; private boolean isFieldAccess; private transient Annotation[] annotations; private static final String WORD_SEPARATOR = "-"; @@ -112,7 +125,7 @@ } else if ( el instanceof Field ) { propertyName = ( (Field) el ).getName(); - isFieldAccess = true; + isField = true; } else if ( el instanceof Method ) { Method method = (Method) el; @@ -130,7 +143,7 @@ } throw new RuntimeException( "Method " + propertyName + " is not a property getter" ); } - isFieldAccess = true; + isField = true; } else { className = null; @@ -206,6 +219,12 @@ if ( current != null ) annotationList.add( current ); current = getExcludeSuperclassListeners( tree, defaults ); if ( current != null ) annotationList.add( current ); + current = getAccessType( tree, defaults ); + if ( current != null ) annotationList.add( current ); + current = getAttributeOverrides( tree, defaults ); + if ( current != null ) annotationList.add( current ); + current = getAssociationOverrides( tree, defaults ); + if ( current != null ) annotationList.add( current ); this.annotations = annotationList.toArray( new Annotation[ annotationList.size() ] ); } else if ( propertyName != null ) { @@ -218,6 +237,173 @@ } } + private AssociationOverrides getAssociationOverrides(Element tree, XMLContext.Default defaults) { + List<AssociationOverride> attributes = (List<AssociationOverride>) buildAssociationOverrides( tree ); + if ( defaults.canUseJavaAnnotations() ) { + AssociationOverride annotation = super.getAnnotation( AssociationOverride.class ); + addAssociationOverrideIfNeeded( annotation, attributes ); + AssociationOverrides annotations = super.getAnnotation( AssociationOverrides.class ); + if (annotations != null) { + for (AssociationOverride current : annotations.value() ) { + addAssociationOverrideIfNeeded( current, attributes ); + } + } + } + if (attributes.size() > 0) { + AnnotationDescriptor ad = new AnnotationDescriptor( AssociationOverrides.class ); + ad.setValue( "value", attributes.toArray( new AssociationOverride[ attributes.size() ] ) ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private List<AssociationOverride> buildAssociationOverrides(Element element) { + List<Element> subelements = element == null ? null : element.elements( "association-override" ); + List<AssociationOverride> overrides = new ArrayList<AssociationOverride>(); + if (subelements != null && subelements.size() > 0) { + for (Element current : subelements) { + AnnotationDescriptor override = new AnnotationDescriptor( AssociationOverride.class ); + copyStringAttribute( override, current, "name", true ); + override.setValue( "joinColumns", getJoinColumns( current ) ); + overrides.add( (AssociationOverride) AnnotationFactory.create( override ) ); + } + } + return overrides; + } + + private JoinColumn[] getJoinColumns(Element element) { + List<Element> subelements = element != null ? element.elements( "join-column" ) : null; + List<JoinColumn> joinColumns = new ArrayList<JoinColumn>(); + if ( subelements != null) { + for (Element subelement : subelements) { + AnnotationDescriptor column = new AnnotationDescriptor( JoinColumn.class ); + copyStringAttribute(column, subelement, "name", false); + copyStringAttribute(column, subelement, "referenced-column-name", false); + copyBooleanAttribute(column, subelement, "unique"); + copyBooleanAttribute(column, subelement, "nullable"); + copyBooleanAttribute(column, subelement, "insertable"); + copyBooleanAttribute(column, subelement, "updatable"); + copyStringAttribute(column, subelement, "column-definition", false); + copyStringAttribute(column, subelement, "table", false); + joinColumns.add( (JoinColumn) AnnotationFactory.create( column ) ); + } + } + return joinColumns.toArray( new JoinColumn[ joinColumns.size() ] ); + } + + private void addAssociationOverrideIfNeeded(AssociationOverride annotation, List<AssociationOverride> overrides) { + if (annotation != null) { + String overrideName = annotation.name(); + boolean present = false; + for (AssociationOverride current : overrides ) { + if ( current.name().equals( overrideName ) ) { + present = true; + break; + } + } + if (!present) overrides.add(annotation); + } + } + + private AttributeOverrides getAttributeOverrides(Element tree, XMLContext.Default defaults) { + List<AttributeOverride> attributes = (List<AttributeOverride>) buildAttributeOverrides( tree ); + if ( defaults.canUseJavaAnnotations() ) { + AttributeOverride annotation = super.getAnnotation( AttributeOverride.class ); + addAttributeOverrideIfNeeded( annotation, attributes ); + AttributeOverrides annotations = super.getAnnotation( AttributeOverrides.class ); + if (annotations != null) { + for (AttributeOverride current : annotations.value() ) { + addAttributeOverrideIfNeeded( current, attributes ); + } + } + } + if (attributes.size() > 0) { + AnnotationDescriptor ad = new AnnotationDescriptor( AttributeOverrides.class ); + ad.setValue( "value", attributes.toArray( new AttributeOverride[ attributes.size() ] ) ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private List<AttributeOverride> buildAttributeOverrides(Element element) { + List<Element> subelements = element == null ? null : element.elements( "attribute-override" ); + List<AttributeOverride> overrides = new ArrayList<AttributeOverride>(); + if (subelements != null && subelements.size() > 0) { + for (Element current : subelements) { + AnnotationDescriptor override = new AnnotationDescriptor( AttributeOverride.class ); + copyStringAttribute( override, current, "name", true ); + override.setValue( "column", getColumn( current, true ) ); + overrides.add( (AttributeOverride) AnnotationFactory.create( override ) ); + } + } + return overrides; + } + + private Column getColumn(Element element, boolean isMandatory) { + Element subelement = element != null ? element.element( "column" ) : null; + if ( subelement != null ) { + AnnotationDescriptor column = new AnnotationDescriptor( Column.class ); + copyStringAttribute(column, subelement, "name", false); + copyBooleanAttribute(column, subelement, "unique"); + copyBooleanAttribute(column, subelement, "nullable"); + copyBooleanAttribute(column, subelement, "insertable"); + copyBooleanAttribute(column, subelement, "updatable"); + copyStringAttribute(column, subelement, "column-definition", false); + copyStringAttribute(column, subelement, "table", false); + copyIntegerAttribute(column, subelement, "length"); + copyIntegerAttribute(column, subelement, "precision"); + copyIntegerAttribute(column, subelement, "scale"); + return (Column) AnnotationFactory.create( column ); + } + else { + if ( isMandatory ) throw new AnnotationException( element.getPath() + ".column is mandatory. " + SCHEMA_VALIDATION); + return null; + } + } + + private void addAttributeOverrideIfNeeded(AttributeOverride annotation, List<AttributeOverride> overrides) { + if (annotation != null) { + String overrideName = annotation.name(); + boolean present = false; + for (AttributeOverride current : overrides ) { + if ( current.name().equals( overrideName ) ) { + present = true; + break; + } + } + if (!present) overrides.add(annotation); + } + } + + private AccessType getAccessType(Element tree, XMLContext.Default defaults) { + String access = tree == null ? null : tree.attributeValue( "access" ); + if (access != null) { + AnnotationDescriptor ad = new AnnotationDescriptor(AccessType.class); + ad.setValue( "value", access ); + isFieldAccess = "field".equalsIgnoreCase( access ); + return AnnotationFactory.create(ad); + } + else if ( defaults.canUseJavaAnnotations() && super.isAnnotationPresent(AccessType.class) ) { + AccessType annotation = super.getAnnotation( AccessType.class ); + isFieldAccess = "field".equalsIgnoreCase( annotation != null ? annotation.value() : null ); + return annotation; + } + else if ( defaults.getAccess() != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor(AccessType.class); + ad.setValue( "value", defaults.getAccess() ); + isFieldAccess = "field".equalsIgnoreCase( defaults.getAccess() ); + return AnnotationFactory.create(ad); + } + else { + isFieldAccess = false; + return null; + } + } + private ExcludeSuperclassListeners getExcludeSuperclassListeners(Element tree, XMLContext.Default defaults) { return (ExcludeSuperclassListeners) getMarkerAnnotation(ExcludeSuperclassListeners.class, tree, defaults); } @@ -866,14 +1052,8 @@ ) { String attribute = element.attributeValue( attributeName ); if (attribute != null) { - StringBuilder annotationAttributeName = new StringBuilder( attributeName ); - int index = annotationAttributeName.indexOf( WORD_SEPARATOR ); - while ( index != -1 ) { - annotationAttributeName.deleteCharAt( index ); - annotationAttributeName.setCharAt( index, Character.toUpperCase( annotationAttributeName.charAt( index ) ) ); - index = annotationAttributeName.indexOf( WORD_SEPARATOR ); - } - annotation.setValue( annotationAttributeName.toString(), attribute ); + String annotationAttributeName = getJavaAttributeNameFromXMLOne( attributeName ); + annotation.setValue( annotationAttributeName, attribute ); } else { if (mandatory) { @@ -885,26 +1065,39 @@ private void copyIntegerAttribute(AnnotationDescriptor annotation, Element element, String attributeName) { String attribute = element.attributeValue( attributeName ); if (attribute != null) { - StringBuilder annotationAttributeName = new StringBuilder( attributeName ); - int index = annotationAttributeName.indexOf( WORD_SEPARATOR ); - while ( index != -1 ) { - annotationAttributeName.deleteCharAt( index ); - annotationAttributeName.setCharAt( index, Character.toUpperCase( annotationAttributeName.charAt( index ) )); - index = annotationAttributeName.indexOf( WORD_SEPARATOR ); - } - annotation.setValue( annotationAttributeName.toString(), attribute ); + String annotationAttributeName = getJavaAttributeNameFromXMLOne( attributeName ); + annotation.setValue( annotationAttributeName, attribute ); try { int length = Integer.parseInt( attribute ); - annotation.setValue( annotationAttributeName.toString(), length ); + annotation.setValue( annotationAttributeName, length ); } catch (NumberFormatException e) { - throw new AnnotationException( attributeName + " not parseable: " + attribute + " (" + SCHEMA_VALIDATION + ")" ); + throw new AnnotationException( element.getPath() + attributeName + " not parseable: " + attribute + " (" + SCHEMA_VALIDATION + ")" ); } } } + private String getJavaAttributeNameFromXMLOne(String attributeName) { + StringBuilder annotationAttributeName = new StringBuilder( attributeName ); + int index = annotationAttributeName.indexOf( WORD_SEPARATOR ); + while ( index != -1 ) { + annotationAttributeName.deleteCharAt( index ); + annotationAttributeName.setCharAt( index, Character.toUpperCase( annotationAttributeName.charAt( index ) )); + index = annotationAttributeName.indexOf( WORD_SEPARATOR ); + } + return annotationAttributeName.toString(); + } + private void copyStringElement(Element element, AnnotationDescriptor ad, String annotationAttribute) { String discr = element.getTextTrim(); ad.setValue( annotationAttribute, discr ); } + + private void copyBooleanAttribute(AnnotationDescriptor descriptor, Element element, String attribute) { + String attributeValue = element.attributeValue( attribute ); + if ( StringHelper.isNotEmpty( attributeValue ) ) { + String javaAttribute = getJavaAttributeNameFromXMLOne( attribute ); + descriptor.setValue( javaAttribute, Boolean.parseBoolean( attributeValue ) ); + } + } } Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/reflection/java/xml/XMLContext.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/reflection/java/xml/XMLContext.java 2006-04-19 01:45:07 UTC (rev 9765) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/reflection/java/xml/XMLContext.java 2006-04-19 02:24:45 UTC (rev 9766) @@ -87,6 +87,8 @@ localDefault.override( defaults ); attribute = element.attribute( "metadata-complete" ); if (attribute != null) localDefault.setMetadataComplete( (Boolean) attribute.getData() ); + String access = element.attributeValue( "access" ); + if (access != null) localDefault.setAccess( access ); defaultsOverriding.put( className, localDefault ); log.debug( "Adding XML overriding information for " + className); Modified: trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/EJB3OverridenAnnotationReaderTest.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/EJB3OverridenAnnotationReaderTest.java 2006-04-19 01:45:07 UTC (rev 9765) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/EJB3OverridenAnnotationReaderTest.java 2006-04-19 02:24:45 UTC (rev 9766) @@ -25,6 +25,8 @@ import javax.persistence.TableGenerator; import javax.persistence.ExcludeSuperclassListeners; import javax.persistence.ExcludeDefaultListeners; +import javax.persistence.AttributeOverrides; +import javax.persistence.AssociationOverrides; import junit.framework.TestCase; import org.dom4j.DocumentException; @@ -100,7 +102,16 @@ assertNull( "Mutualize PKJC into PKJCs", reader.getAnnotation( PrimaryKeyJoinColumn.class) ); assertNotNull( reader.getAnnotation( PrimaryKeyJoinColumns.class) ); assertEquals( "PrimaryKeyJoinColumn overrden", "id", reader.getAnnotation( PrimaryKeyJoinColumns.class).value()[0].name() ); + assertNotNull( reader.getAnnotation( AttributeOverrides.class ) ); + assertEquals( "Wrong deduplication", 3, reader.getAnnotation( AttributeOverrides.class ).value().length ); + assertEquals( "Wrong priority (XML vs java annotations)", "fld_net", reader.getAnnotation( AttributeOverrides.class ).value()[0].column().name() ); + assertEquals( "Column mapping", 2, reader.getAnnotation( AttributeOverrides.class ).value()[1].column().scale() ); + assertEquals( "Column mapping", true, reader.getAnnotation( AttributeOverrides.class ).value()[1].column().unique() ); + assertNotNull( reader.getAnnotation( AssociationOverrides.class ) ); + assertEquals( "no XML processing", 1, reader.getAnnotation( AssociationOverrides.class ).value().length ); + assertEquals( "wrong xml processing", "id", reader.getAnnotation( AssociationOverrides.class ).value()[0].joinColumns()[0].referencedColumnName() ); + reader = new EJB3OverridenAnnotationReader(SocialSecurityPhysicalAccount.class, context); assertNotNull( reader.getAnnotation( IdClass.class ) ); assertEquals( "id-class not used", SocialSecurityNumber.class, reader.getAnnotation( IdClass.class ).value() ); Modified: trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/TennisMatch.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/TennisMatch.java 2006-04-19 01:45:07 UTC (rev 9765) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/TennisMatch.java 2006-04-19 02:24:45 UTC (rev 9766) @@ -1,14 +1,21 @@ //$Id: $ package org.hibernate.test.reflection.java.xml; +import javax.persistence.AttributeOverride; +import javax.persistence.AttributeOverrides; import javax.persistence.Entity; import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.Column; /** * @author Emmanuel Bernard */ @Entity -@PrimaryKeyJoinColumn(name="match_id") +@PrimaryKeyJoinColumn(name = "match_id") +@AttributeOverrides( + {@AttributeOverride(name = "net", column = @Column(name="net") ), + @AttributeOverride(name = "line", column = @Column(name="line") ) + } ) public class TennisMatch { } Modified: trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/orm.xml =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/orm.xml 2006-04-19 01:45:07 UTC (rev 9765) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/reflection/java/xml/orm.xml 2006-04-19 02:24:45 UTC (rev 9766) @@ -58,6 +58,15 @@ </entity> <entity class="TennisMatch"> <primary-key-join-column name="id"/> + <attribute-override name="net"> + <column name="fld_net"/> + </attribute-override> + <attribute-override name="ground"> + <column name="fld_ground" unique="true" scale="2"/> + </attribute-override> + <association-override name="referer"> + <join-column name="referer_id" referenced-column-name="id"/> + </association-override> </entity> <entity class="SocialSecurityPhysicalAccount"> <id-class class="org.hibernate.test.reflection.java.xml.SocialSecurityNumber"/> |