HHH-18095 - transform column read/write fragments
This commit is contained in:
parent
61a00b1e6c
commit
086c7208cb
|
@ -91,6 +91,20 @@ public class AdditionalManagedResourcesImpl implements ManagedResources {
|
||||||
private List<String> packageNames;
|
private List<String> packageNames;
|
||||||
private Collection<Binding<JaxbBindableMappingDescriptor>> xmlMappings;
|
private Collection<Binding<JaxbBindableMappingDescriptor>> xmlMappings;
|
||||||
|
|
||||||
|
public Builder(boolean validateMappings, boolean transformHbmMappings) {
|
||||||
|
this( new MappingBinder.Options() {
|
||||||
|
@Override
|
||||||
|
public boolean validateMappings() {
|
||||||
|
return validateMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean transformHbmMappings() {
|
||||||
|
return transformHbmMappings;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
public Builder() {
|
public Builder() {
|
||||||
this( new MappingBinder.Options() {
|
this( new MappingBinder.Options() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,6 +17,7 @@ import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.AnnotationException;
|
import org.hibernate.AnnotationException;
|
||||||
import org.hibernate.annotations.CascadeType;
|
import org.hibernate.annotations.CascadeType;
|
||||||
|
import org.hibernate.annotations.ColumnTransformer;
|
||||||
import org.hibernate.annotations.NotFoundAction;
|
import org.hibernate.annotations.NotFoundAction;
|
||||||
import org.hibernate.annotations.Parameter;
|
import org.hibernate.annotations.Parameter;
|
||||||
import org.hibernate.annotations.ResultCheckStyle;
|
import org.hibernate.annotations.ResultCheckStyle;
|
||||||
|
@ -73,6 +74,7 @@ import org.hibernate.boot.models.annotations.internal.CheckConstraintJpaAnnotati
|
||||||
import org.hibernate.boot.models.annotations.internal.CollectionIdAnnotation;
|
import org.hibernate.boot.models.annotations.internal.CollectionIdAnnotation;
|
||||||
import org.hibernate.boot.models.annotations.internal.CollectionTypeAnnotation;
|
import org.hibernate.boot.models.annotations.internal.CollectionTypeAnnotation;
|
||||||
import org.hibernate.boot.models.annotations.internal.ColumnJpaAnnotation;
|
import org.hibernate.boot.models.annotations.internal.ColumnJpaAnnotation;
|
||||||
|
import org.hibernate.boot.models.annotations.internal.ColumnTransformerAnnotation;
|
||||||
import org.hibernate.boot.models.annotations.internal.ConvertJpaAnnotation;
|
import org.hibernate.boot.models.annotations.internal.ConvertJpaAnnotation;
|
||||||
import org.hibernate.boot.models.annotations.internal.ConvertsJpaAnnotation;
|
import org.hibernate.boot.models.annotations.internal.ConvertsJpaAnnotation;
|
||||||
import org.hibernate.boot.models.annotations.internal.DiscriminatorColumnJpaAnnotation;
|
import org.hibernate.boot.models.annotations.internal.DiscriminatorColumnJpaAnnotation;
|
||||||
|
@ -197,19 +199,44 @@ public class XmlAnnotationHelper {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
createColumnAnnotation( jaxbColumn, memberDetails, xmlDocumentContext );
|
final ColumnJpaAnnotation columnAnnotationUsage = (ColumnJpaAnnotation) memberDetails.applyAnnotationUsage(
|
||||||
|
COLUMN,
|
||||||
|
xmlDocumentContext.getModelBuildingContext()
|
||||||
|
);
|
||||||
|
columnAnnotationUsage.apply( jaxbColumn, xmlDocumentContext );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ColumnJpaAnnotation createColumnAnnotation(
|
private static ColumnJpaAnnotation createColumnAnnotation(
|
||||||
JaxbColumnImpl jaxbColumn,
|
JaxbColumnImpl jaxbColumn,
|
||||||
MutableAnnotationTarget target,
|
MutableAnnotationTarget target,
|
||||||
XmlDocumentContext xmlDocumentContext) {
|
XmlDocumentContext xmlDocumentContext) {
|
||||||
final ColumnJpaAnnotation columnAnnotationUsage = (ColumnJpaAnnotation) target.applyAnnotationUsage(
|
final ColumnJpaAnnotation usage = COLUMN.createUsage( xmlDocumentContext.getModelBuildingContext() );
|
||||||
COLUMN,
|
usage.apply( jaxbColumn, xmlDocumentContext );
|
||||||
|
return usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void applyColumnTransformation(
|
||||||
|
JaxbColumnImpl jaxbColumn,
|
||||||
|
MutableMemberDetails memberDetails,
|
||||||
|
XmlDocumentContext xmlDocumentContext) {
|
||||||
|
if ( StringHelper.isEmpty( jaxbColumn.getRead() )
|
||||||
|
&& StringHelper.isEmpty( jaxbColumn.getWrite() ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ColumnTransformerAnnotation annotationUsage = (ColumnTransformerAnnotation) memberDetails.applyAnnotationUsage(
|
||||||
|
HibernateAnnotations.COLUMN_TRANSFORMER,
|
||||||
xmlDocumentContext.getModelBuildingContext()
|
xmlDocumentContext.getModelBuildingContext()
|
||||||
);
|
);
|
||||||
columnAnnotationUsage.apply( jaxbColumn, xmlDocumentContext );
|
|
||||||
return columnAnnotationUsage;
|
annotationUsage.forColumn( jaxbColumn.getName() );
|
||||||
|
|
||||||
|
if ( StringHelper.isNotEmpty( jaxbColumn.getRead() ) ) {
|
||||||
|
annotationUsage.read( jaxbColumn.getRead() );
|
||||||
|
}
|
||||||
|
if ( StringHelper.isNotEmpty( jaxbColumn.getWrite() ) ) {
|
||||||
|
annotationUsage.write( jaxbColumn.getWrite() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void applyUserType(
|
public static void applyUserType(
|
||||||
|
|
|
@ -70,6 +70,7 @@ public class BasicAttributeProcessing {
|
||||||
xmlDocumentContext.getModelBuildingContext()
|
xmlDocumentContext.getModelBuildingContext()
|
||||||
);
|
);
|
||||||
columnAnn.apply( jaxbBasic.getColumn(), xmlDocumentContext );
|
columnAnn.apply( jaxbBasic.getColumn(), xmlDocumentContext );
|
||||||
|
XmlAnnotationHelper.applyColumnTransformation( jaxbBasic.getColumn(), memberDetails, xmlDocumentContext );
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlAnnotationHelper.applyConvert( jaxbBasic.getConvert(), memberDetails, xmlDocumentContext );
|
XmlAnnotationHelper.applyConvert( jaxbBasic.getConvert(), memberDetails, xmlDocumentContext );
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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.models.xml.column.transform;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class Item {
|
||||||
|
private Integer id;
|
||||||
|
private String name;
|
||||||
|
private double cost;
|
||||||
|
|
||||||
|
protected Item() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public Item(Integer id, String name, double cost) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.cost = cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getCost() {
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCost(double cost) {
|
||||||
|
this.cost = cost;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* 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.models.xml.column.transform;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.ColumnTransformer;
|
||||||
|
import org.hibernate.boot.internal.BootstrapContextImpl;
|
||||||
|
import org.hibernate.boot.internal.MetadataBuilderImpl;
|
||||||
|
import org.hibernate.boot.model.process.spi.ManagedResources;
|
||||||
|
import org.hibernate.boot.model.source.internal.annotations.AdditionalManagedResourcesImpl;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||||
|
import org.hibernate.mapping.Column;
|
||||||
|
import org.hibernate.mapping.Property;
|
||||||
|
import org.hibernate.models.spi.ClassDetails;
|
||||||
|
import org.hibernate.models.spi.FieldDetails;
|
||||||
|
import org.hibernate.models.spi.SourceModelBuildingContext;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.hibernate.orm.test.boot.models.SourceModelTestHelper.createBuildingContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||||
|
public class ModelTests {
|
||||||
|
@ServiceRegistry
|
||||||
|
@Test
|
||||||
|
void testMappingXml(ServiceRegistryScope scope) {
|
||||||
|
final ManagedResources managedResources = new AdditionalManagedResourcesImpl.Builder()
|
||||||
|
.addXmlMappings( "mappings/models/column/transform/mapping.xml" )
|
||||||
|
.build();
|
||||||
|
final StandardServiceRegistry serviceRegistry = scope.getRegistry();
|
||||||
|
final BootstrapContextImpl bootstrapContext = new BootstrapContextImpl(
|
||||||
|
serviceRegistry,
|
||||||
|
new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry )
|
||||||
|
);
|
||||||
|
|
||||||
|
final SourceModelBuildingContext sourceModelBuildingContext = createBuildingContext(
|
||||||
|
managedResources,
|
||||||
|
false,
|
||||||
|
new MetadataBuilderImpl.MetadataBuildingOptionsImpl( bootstrapContext.getServiceRegistry() ),
|
||||||
|
bootstrapContext
|
||||||
|
);
|
||||||
|
|
||||||
|
final ClassDetails classDetails = sourceModelBuildingContext.getClassDetailsRegistry().getClassDetails( Item.class.getName() );
|
||||||
|
final FieldDetails costField = classDetails.findFieldByName( "cost" );
|
||||||
|
final ColumnTransformer transformerAnn = costField.getAnnotationUsage( ColumnTransformer.class, sourceModelBuildingContext );
|
||||||
|
assertThat( transformerAnn ).isNotNull();
|
||||||
|
assertThat( transformerAnn.read() ).isEqualTo( "cost / 100.00" );
|
||||||
|
assertThat( transformerAnn.write() ).isEqualTo( "? * 100.00" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@ServiceRegistry
|
||||||
|
@Test
|
||||||
|
void testHbmXml(ServiceRegistryScope scope) {
|
||||||
|
final ManagedResources managedResources = new AdditionalManagedResourcesImpl.Builder( true, true )
|
||||||
|
.addXmlMappings( "mappings/models/column/transform/hbm.xml" )
|
||||||
|
.build();
|
||||||
|
final StandardServiceRegistry serviceRegistry = scope.getRegistry();
|
||||||
|
final BootstrapContextImpl bootstrapContext = new BootstrapContextImpl(
|
||||||
|
serviceRegistry,
|
||||||
|
new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry )
|
||||||
|
);
|
||||||
|
|
||||||
|
final SourceModelBuildingContext sourceModelBuildingContext = createBuildingContext(
|
||||||
|
managedResources,
|
||||||
|
false,
|
||||||
|
new MetadataBuilderImpl.MetadataBuildingOptionsImpl( bootstrapContext.getServiceRegistry() ),
|
||||||
|
bootstrapContext
|
||||||
|
);
|
||||||
|
|
||||||
|
final ClassDetails classDetails = sourceModelBuildingContext.getClassDetailsRegistry().getClassDetails( Item.class.getName() );
|
||||||
|
final FieldDetails costField = classDetails.findFieldByName( "cost" );
|
||||||
|
final ColumnTransformer transformerAnn = costField.getAnnotationUsage( ColumnTransformer.class, sourceModelBuildingContext );
|
||||||
|
assertThat( transformerAnn ).isNotNull();
|
||||||
|
assertThat( transformerAnn.read() ).isEqualTo( "cost / 100.00" );
|
||||||
|
assertThat( transformerAnn.write() ).isEqualTo( "? * 100.00" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@ServiceRegistry
|
||||||
|
@DomainModel(xmlMappings = "mappings/models/column/transform/mapping.xml")
|
||||||
|
@Test
|
||||||
|
void testMappingModel(DomainModelScope domainModelScope) {
|
||||||
|
domainModelScope.withHierarchy( Item.class, (rootClass) -> {
|
||||||
|
final Property costProperty = rootClass.getProperty( "cost" );
|
||||||
|
assertThat( costProperty.getColumns() ).hasSize( 1 );
|
||||||
|
final Column column = costProperty.getColumns().get( 0 );
|
||||||
|
assertThat( column.getCustomRead() ).isEqualTo( "cost / 100.00" );
|
||||||
|
assertThat( column.getCustomWrite() ).isEqualTo( "? * 100.00" );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
<hibernate-mapping
|
||||||
|
xmlns="http://www.hibernate.org/xsd/orm/hbm"
|
||||||
|
default-access="field"
|
||||||
|
package="org.hibernate.orm.test.boot.models.xml.column.transform">
|
||||||
|
<class name="Item" >
|
||||||
|
<id name="id"/>
|
||||||
|
<property name="name"/>
|
||||||
|
<property name="cost">
|
||||||
|
<column name="cost" read="cost / 100.00" write="? * 100.00"/>
|
||||||
|
</property>
|
||||||
|
</class>
|
||||||
|
</hibernate-mapping>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<!--
|
||||||
|
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
~
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
~ Copyright: Red Hat Inc. and Hibernate Authors
|
||||||
|
-->
|
||||||
|
<entity-mappings xmlns="http://www.hibernate.org/xsd/orm/mapping"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
version="7.0">
|
||||||
|
<package>org.hibernate.orm.test.boot.models.xml.column.transform</package>
|
||||||
|
<entity class="Item" metadata-complete="true" access="FIELD">
|
||||||
|
<table name="items"/>
|
||||||
|
<attributes>
|
||||||
|
<id name="id"/>
|
||||||
|
<basic name="name"/>
|
||||||
|
<basic name="cost">
|
||||||
|
<column>
|
||||||
|
<read>cost / 100.00</read>
|
||||||
|
<write>? * 100.00</write>
|
||||||
|
</column>
|
||||||
|
<jdbc-type-code>2</jdbc-type-code>
|
||||||
|
</basic>
|
||||||
|
</attributes>
|
||||||
|
</entity>
|
||||||
|
</entity-mappings>
|
Loading…
Reference in New Issue