HHH-16990 Add support for more hibernate-specific features to XML mappings
- org.hibernate.annotations.Type - org.hibernate.annotations.JdbcTypeCode - org.hibernate.annotations.UuidGenerator
This commit is contained in:
parent
7edb7984a8
commit
ae8b3f9a33
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.boot.jaxb.mapping.marshall;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.annotations.UuidGenerator;
|
||||
|
||||
/**
|
||||
* JAXB marshalling for {@link UuidGenerator.Style}
|
||||
*/
|
||||
public class UuidGeneratorStyleMarshalling {
|
||||
public static UuidGenerator.Style fromXml(String name) {
|
||||
return name == null ? null : UuidGenerator.Style.valueOf( name.toUpperCase( Locale.ROOT ) );
|
||||
}
|
||||
|
||||
public static String toXml(UuidGenerator.Style style) {
|
||||
return style == null ? null : style.name().toLowerCase( Locale.ROOT );
|
||||
}
|
||||
}
|
|
@ -28,8 +28,12 @@ import org.hibernate.annotations.Cache;
|
|||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.Cascade;
|
||||
import org.hibernate.annotations.Columns;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.annotations.ManyToAny;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
import org.hibernate.annotations.Subselect;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.annotations.UuidGenerator;
|
||||
import org.hibernate.annotations.common.annotationfactory.AnnotationDescriptor;
|
||||
import org.hibernate.annotations.common.annotationfactory.AnnotationFactory;
|
||||
import org.hibernate.annotations.common.reflection.AnnotationReader;
|
||||
|
@ -46,6 +50,8 @@ import org.hibernate.boot.jaxb.mapping.JaxbCascadeType;
|
|||
import org.hibernate.boot.jaxb.mapping.JaxbCollectionTable;
|
||||
import org.hibernate.boot.jaxb.mapping.JaxbColumn;
|
||||
import org.hibernate.boot.jaxb.mapping.JaxbColumnResult;
|
||||
import org.hibernate.boot.jaxb.mapping.JaxbColumnType;
|
||||
import org.hibernate.boot.jaxb.mapping.JaxbConfigurationParameter;
|
||||
import org.hibernate.boot.jaxb.mapping.JaxbConstructorResult;
|
||||
import org.hibernate.boot.jaxb.mapping.JaxbConvert;
|
||||
import org.hibernate.boot.jaxb.mapping.JaxbDiscriminatorColumn;
|
||||
|
@ -93,6 +99,7 @@ import org.hibernate.boot.jaxb.mapping.JaxbSynchronizedTable;
|
|||
import org.hibernate.boot.jaxb.mapping.JaxbTable;
|
||||
import org.hibernate.boot.jaxb.mapping.JaxbTableGenerator;
|
||||
import org.hibernate.boot.jaxb.mapping.JaxbUniqueConstraint;
|
||||
import org.hibernate.boot.jaxb.mapping.JaxbUuidGenerator;
|
||||
import org.hibernate.boot.jaxb.mapping.JaxbVersion;
|
||||
import org.hibernate.boot.jaxb.mapping.LifecycleCallbackContainer;
|
||||
import org.hibernate.boot.jaxb.mapping.ManagedType;
|
||||
|
@ -255,6 +262,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
|
|||
annotationToXml.put( ExcludeDefaultListeners.class, "exclude-default-listeners" );
|
||||
annotationToXml.put( ExcludeSuperclassListeners.class, "exclude-superclass-listeners" );
|
||||
// annotationToXml.put( AccessType.class, "access" );
|
||||
// FIXME: adding same annotation as a key multiple times:
|
||||
annotationToXml.put( AttributeOverride.class, "attribute-override" );
|
||||
annotationToXml.put( AttributeOverrides.class, "attribute-override" );
|
||||
annotationToXml.put( AttributeOverride.class, "association-override" );
|
||||
|
@ -306,7 +314,9 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
|
|||
annotationToXml.put( Convert.class, "convert" );
|
||||
annotationToXml.put( Converts.class, "convert" );
|
||||
annotationToXml.put( ConstructorResult.class, "constructor-result" );
|
||||
|
||||
annotationToXml.put( Type.class, "type" );
|
||||
annotationToXml.put( JdbcTypeCode.class, "jdbc-type-code" );
|
||||
annotationToXml.put( UuidGenerator.class, "uuid-generator" );
|
||||
}
|
||||
|
||||
private final XMLContext xmlContext;
|
||||
|
@ -1592,6 +1602,8 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
|
|||
getFetchType( basic, element.getFetch() );
|
||||
copyAttribute( basic, "optional", element.isOptional(), false );
|
||||
annotationList.add( AnnotationFactory.create( basic ) );
|
||||
getType( annotationList, element.getType() );
|
||||
getJdbcTypeCode( annotationList, element.getJdbcTypeCode() );
|
||||
}
|
||||
if ( elementsForProperty.isEmpty() && defaults.canUseJavaAnnotations() ) {
|
||||
//no annotation presence constraint, basic is the default
|
||||
|
@ -1618,6 +1630,40 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
|
|||
}
|
||||
}
|
||||
|
||||
private void getType(List<Annotation> annotationList, JaxbColumnType type) {
|
||||
if ( type != null ) {
|
||||
AnnotationDescriptor ad = new AnnotationDescriptor( Type.class );
|
||||
ad.setValue( "value", classLoaderAccess.classForName( type.getValue() ) );
|
||||
Parameter[] parameters = new Parameter[type.getParameters().size()];
|
||||
for ( int i = 0; i < parameters.length; i++ ) {
|
||||
JaxbConfigurationParameter parameter = type.getParameters().get( i );
|
||||
AnnotationDescriptor param = new AnnotationDescriptor( Parameter.class );
|
||||
param.setValue( "name", parameter.getName() );
|
||||
param.setValue( "value", parameter.getValue() );
|
||||
parameters[i] = AnnotationFactory.create( param );
|
||||
}
|
||||
ad.setValue( "parameters", parameters );
|
||||
|
||||
annotationList.add( AnnotationFactory.create( ad ) );
|
||||
}
|
||||
}
|
||||
|
||||
private void getUuidGenerator(List<Annotation> annotationList, JaxbUuidGenerator uuidGenerator) {
|
||||
if ( uuidGenerator != null ) {
|
||||
AnnotationDescriptor ad = new AnnotationDescriptor( UuidGenerator.class );
|
||||
ad.setValue( "style", uuidGenerator.getStyle() );
|
||||
annotationList.add( AnnotationFactory.create( ad ) );
|
||||
}
|
||||
}
|
||||
|
||||
private void getJdbcTypeCode(List<Annotation> annotationList, Integer jdbcTypeCode) {
|
||||
if ( jdbcTypeCode != null ) {
|
||||
AnnotationDescriptor ad = new AnnotationDescriptor( JdbcTypeCode.class );
|
||||
ad.setValue( "value", jdbcTypeCode );
|
||||
annotationList.add( AnnotationFactory.create( ad ) );
|
||||
}
|
||||
}
|
||||
|
||||
private void getEnumerated(List<Annotation> annotationList, EnumType enumType) {
|
||||
if ( enumType != null ) {
|
||||
AnnotationDescriptor ad = new AnnotationDescriptor( Enumerated.class );
|
||||
|
@ -1710,6 +1756,8 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
|
|||
AnnotationDescriptor id = new AnnotationDescriptor( Id.class );
|
||||
annotationList.add( AnnotationFactory.create( id ) );
|
||||
getAccessType( annotationList, element.getAccess() );
|
||||
getType( annotationList, element.getType() );
|
||||
getUuidGenerator( annotationList, element.getUuidGenerator() );
|
||||
}
|
||||
}
|
||||
if ( elementsForProperty.isEmpty() && defaults.canUseJavaAnnotations() ) {
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.boot.model.internal;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -1304,7 +1305,7 @@ public class PropertyBinder {
|
|||
final XProperty idProperty = inferredData.getProperty();
|
||||
final List<Annotation> idGeneratorAnnotations = findContainingAnnotations( idProperty, IdGeneratorType.class );
|
||||
final List<Annotation> generatorAnnotations = findContainingAnnotations( idProperty, ValueGenerationType.class );
|
||||
generatorAnnotations.removeAll( idGeneratorAnnotations );
|
||||
removeIdGenerators( generatorAnnotations, idGeneratorAnnotations );
|
||||
if ( idGeneratorAnnotations.size() + generatorAnnotations.size() > 1 ) {
|
||||
throw new AnnotationException( "Property '"+ getPath( propertyHolder, inferredData )
|
||||
+ "' has too many generator annotations " + combine( idGeneratorAnnotations, generatorAnnotations ) );
|
||||
|
@ -1330,4 +1331,20 @@ public class PropertyBinder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since these collections may contain Proxies created by common-annotations module we cannot reliably use simple remove/removeAll
|
||||
// collection methods as those proxies do not implement hashcode/equals and even a simple `a.equals(a)` will return `false`.
|
||||
// Instead, we will check the annotation types, since generator annotations should not be "repeatable" we should have only
|
||||
// at most one annotation for a generator:
|
||||
private static void removeIdGenerators(List<Annotation> generatorAnnotations, List<Annotation> idGeneratorAnnotations) {
|
||||
for ( Annotation id : idGeneratorAnnotations ) {
|
||||
Iterator<Annotation> iterator = generatorAnnotations.iterator();
|
||||
while ( iterator.hasNext() ) {
|
||||
Annotation gen = iterator.next();
|
||||
if ( gen.annotationType().equals( id.annotationType() ) ) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -519,7 +519,6 @@
|
|||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
See `@org.hibernate.annotations.TenantId`
|
||||
See `@org.hibernate.annotations.TenantId`
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
|
@ -598,6 +597,8 @@
|
|||
See `@org.hibernate.annotations.Nationalized`
|
||||
See `@org.hibernate.annotations.OptimisticLock`
|
||||
See `@org.hibernate.annotations.AttributeAccessor`
|
||||
See `@org.hibernate.annotations.Type`
|
||||
See `@org.hibernate.annotations.JdbcTypeCode`
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
|
@ -614,6 +615,7 @@
|
|||
</xsd:choice>
|
||||
|
||||
<xsd:element name="generated" minOccurs="0" type="orm:basic-generation-timing-type"/>
|
||||
<xsd:element name="type" type="orm:column-type" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
|
@ -623,6 +625,7 @@
|
|||
<!-- hbm: Hibernate's pluggable accessor spi -->
|
||||
<xsd:attribute name="attribute-accessor" type="xsd:string" />
|
||||
<xsd:attribute name="optimistic-lock" type="xsd:boolean" default="true" />
|
||||
<xsd:attribute name="jdbc-type-code" type="xsd:int" />
|
||||
</xsd:complexType>
|
||||
|
||||
|
||||
|
@ -1058,6 +1061,9 @@
|
|||
<xsd:documentation>
|
||||
See `@jakarta.persistence.Id`
|
||||
See `@org.hibernate.annotations.AttributeAccessor`
|
||||
See `@org.hibernate.annotations.Type`
|
||||
See `@org.hibernate.annotations.JdbcTypeCode`
|
||||
See `@org.hibernate.annotations.UuidGenerator`
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
|
@ -1068,12 +1074,15 @@
|
|||
|
||||
<xsd:element name="table-generator" type="orm:table-generator" minOccurs="0"/>
|
||||
<xsd:element name="sequence-generator" type="orm:sequence-generator" minOccurs="0"/>
|
||||
<xsd:element name="uuid-generator" type="orm:uuid-generator" minOccurs="0"/>
|
||||
|
||||
<xsd:element name="unsaved-value" type="xsd:string" minOccurs="0"/>
|
||||
<xsd:element name="type" type="orm:column-type" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="access" type="orm:access-type"/>
|
||||
<xsd:attribute name="attribute-accessor" type="xsd:string" />
|
||||
<xsd:attribute name="jdbc-type-code" type="xsd:int" />
|
||||
</xsd:complexType>
|
||||
|
||||
<!-- **************************************************** -->
|
||||
|
@ -2815,4 +2824,42 @@
|
|||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<!-- **************************************************** -->
|
||||
|
||||
<xsd:complexType name="column-type">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
See `@org.hibernate.annotations.Type`
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="parameters" minOccurs="0" maxOccurs="unbounded" type="configuration-parameter"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="value" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
|
||||
<!-- **************************************************** -->
|
||||
|
||||
<xsd:simpleType name="uuid-generator-style">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
org.hibernate.annotations.UuidGenerator.Style enum values
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="auto"/>
|
||||
<xsd:enumeration value="random"/>
|
||||
<xsd:enumeration value="time"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<xsd:complexType name="uuid-generator">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
See `@org.hibernate.annotations.UuidGenerator`
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="style" type="orm:uuid-generator-style" use="required"/>
|
||||
</xsd:complexType>
|
||||
|
||||
</xsd:schema>
|
||||
|
|
|
@ -423,6 +423,12 @@
|
|||
printMethod="org.hibernate.boot.jaxb.mapping.marshall.CollectionClassificationMarshalling.toXml" />
|
||||
</bindings>
|
||||
|
||||
<bindings node="//xsd:simpleType[@name='uuid-generator-style']">
|
||||
<javaType name="org.hibernate.annotations.UuidGenerator.Style"
|
||||
parseMethod="org.hibernate.boot.jaxb.mapping.marshall.UuidGeneratorStyleMarshalling.fromXml"
|
||||
printMethod="org.hibernate.boot.jaxb.mapping.marshall.UuidGeneratorStyleMarshalling.toXml" />
|
||||
</bindings>
|
||||
|
||||
</bindings>
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.orm.test.boot.jaxb.mapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.hibernate.boot.model.process.internal.UserTypeResolution;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.id.uuid.UuidGenerator;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.usertype.UserTypeSupport;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@DomainModel(annotatedClasses = HibernateOrmSpecificAttributesMappingTest.MyEntity.class, xmlMappings = "xml/jaxb/mapping/partial/hibernate-orm-specific-attributes.xml")
|
||||
public class HibernateOrmSpecificAttributesMappingTest {
|
||||
@Test
|
||||
public void verifyMapping(DomainModelScope scope) {
|
||||
scope.withHierarchy( HibernateOrmSpecificAttributesMappingTest.MyEntity.class, (entityDescriptor) -> {
|
||||
Generator generator = entityDescriptor.getIdentifierProperty().createGenerator( null );
|
||||
assertThat( generator )
|
||||
.isInstanceOf( UuidGenerator.class );
|
||||
|
||||
Property name = entityDescriptor.getProperty( "name" );
|
||||
assertThat( name.getValue() )
|
||||
.isInstanceOf( BasicValue.class );
|
||||
assertThat( ( (BasicValue) name.getValue() ).getExplicitJdbcTypeCode() )
|
||||
.isEqualTo( SqlTypes.CLOB );
|
||||
|
||||
Property tags = entityDescriptor.getProperty( "tags" );
|
||||
assertThat( tags.getValue() )
|
||||
.isInstanceOf( BasicValue.class );
|
||||
assertThat( ( (BasicValue) tags.getValue() ).getResolution() )
|
||||
.isInstanceOf( UserTypeResolution.class );
|
||||
} );
|
||||
}
|
||||
|
||||
public static class MyEntity {
|
||||
private UUID id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Set<String> tags;
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Set<String> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void setTags(Set<String> tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DelimitedStringsJavaType extends UserTypeSupport<Set> {
|
||||
public DelimitedStringsJavaType() {
|
||||
super( Set.class, Types.VARCHAR );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ 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 http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
-->
|
||||
<entity-mappings xmlns="http://www.hibernate.org/xsd/orm/mapping" version="3.1">
|
||||
<package>org.hibernate.orm.test.boot.jaxb.mapping</package>
|
||||
<entity class="HibernateOrmSpecificAttributesMappingTest$MyEntity">
|
||||
<attributes>
|
||||
<id name="id">
|
||||
<uuid-generator style="time"/>
|
||||
</id>
|
||||
<basic name="name" jdbc-type-code="2005"/>
|
||||
<basic name="tags">
|
||||
<type value="org.hibernate.orm.test.boot.jaxb.mapping.HibernateOrmSpecificAttributesMappingTest$DelimitedStringsJavaType"/>
|
||||
</basic>
|
||||
</attributes>
|
||||
</entity>
|
||||
</entity-mappings>
|
Loading…
Reference in New Issue