HHH-10818 - Allow AttributeConverter on attributes marked as Lob (REALLY this time)
This commit is contained in:
parent
b6aa191720
commit
9aa164ed27
|
@ -28,6 +28,7 @@ import org.hibernate.cfg.AvailableSettings;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||||
import org.hibernate.engine.config.spi.StandardConverters;
|
import org.hibernate.engine.config.spi.StandardConverters;
|
||||||
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
import org.hibernate.engine.spi.Mapping;
|
import org.hibernate.engine.spi.Mapping;
|
||||||
import org.hibernate.id.IdentifierGenerator;
|
import org.hibernate.id.IdentifierGenerator;
|
||||||
import org.hibernate.id.IdentityGenerator;
|
import org.hibernate.id.IdentityGenerator;
|
||||||
|
@ -565,11 +566,18 @@ public class SimpleValue implements KeyValue {
|
||||||
if ( isNationalized() ) {
|
if ( isNationalized() ) {
|
||||||
jdbcTypeCode = NationalizedTypeMappings.INSTANCE.getCorrespondingNationalizedCode( jdbcTypeCode );
|
jdbcTypeCode = NationalizedTypeMappings.INSTANCE.getCorrespondingNationalizedCode( jdbcTypeCode );
|
||||||
}
|
}
|
||||||
// find the standard SqlTypeDescriptor for that JDBC type code.
|
|
||||||
final SqlTypeDescriptor sqlTypeDescriptor = SqlTypeDescriptorRegistry.INSTANCE.getDescriptor( jdbcTypeCode );
|
// find the standard SqlTypeDescriptor for that JDBC type code (allow itr to be remapped if needed!)
|
||||||
|
final SqlTypeDescriptor sqlTypeDescriptor = metadata.getMetadataBuildingOptions().getServiceRegistry()
|
||||||
|
.getService( JdbcServices.class )
|
||||||
|
.getJdbcEnvironment()
|
||||||
|
.getDialect()
|
||||||
|
.remapSqlTypeDescriptor( SqlTypeDescriptorRegistry.INSTANCE.getDescriptor( jdbcTypeCode ) );
|
||||||
|
|
||||||
// find the JavaTypeDescriptor representing the "intermediate database type representation". Back to the
|
// find the JavaTypeDescriptor representing the "intermediate database type representation". Back to the
|
||||||
// illustration, this should be the type descriptor for Strings
|
// illustration, this should be the type descriptor for Strings
|
||||||
final JavaTypeDescriptor intermediateJavaTypeDescriptor = JavaTypeDescriptorRegistry.INSTANCE.getDescriptor( databaseColumnJavaType );
|
final JavaTypeDescriptor intermediateJavaTypeDescriptor = JavaTypeDescriptorRegistry.INSTANCE.getDescriptor( databaseColumnJavaType );
|
||||||
|
|
||||||
// and finally construct the adapter, which injects the AttributeConverter calls into the binding/extraction
|
// and finally construct the adapter, which injects the AttributeConverter calls into the binding/extraction
|
||||||
// process...
|
// process...
|
||||||
final SqlTypeDescriptor sqlTypeDescriptorAdapter = new AttributeConverterSqlTypeDescriptorAdapter(
|
final SqlTypeDescriptor sqlTypeDescriptorAdapter = new AttributeConverterSqlTypeDescriptorAdapter(
|
||||||
|
|
|
@ -55,10 +55,9 @@ public class AttributeConverterSqlTypeDescriptorAdapter implements SqlTypeDescri
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canBeRemapped() {
|
public boolean canBeRemapped() {
|
||||||
// todo : consider the ramifications of this.
|
// any remapping of the underlying SqlTypeDescriptor should have
|
||||||
// certainly we need to account for the remapping of the delegate sql-type, but is it really valid to
|
// happened prior to it being passed to us.
|
||||||
// allow remapping of the converter sql-type?
|
return false;
|
||||||
return delegate.canBeRemapped();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* 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.test.converter.caching;
|
||||||
|
|
||||||
|
import javax.persistence.Cacheable;
|
||||||
|
import javax.persistence.Convert;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Lob;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Cache;
|
||||||
|
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Cacheable
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||||
|
public class Address {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
private String streetLine1;
|
||||||
|
private String streetLine2;
|
||||||
|
@Convert(converter = PostalAreaConverter.class)
|
||||||
|
private PostalArea postalArea;
|
||||||
|
|
||||||
|
public Address() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address(
|
||||||
|
Integer id,
|
||||||
|
String streetLine1,
|
||||||
|
String streetLine2,
|
||||||
|
PostalArea postalArea) {
|
||||||
|
this.id = id;
|
||||||
|
this.streetLine1 = streetLine1;
|
||||||
|
this.streetLine2 = streetLine2;
|
||||||
|
this.postalArea = postalArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStreetLine1() {
|
||||||
|
return streetLine1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStreetLine1(String streetLine1) {
|
||||||
|
this.streetLine1 = streetLine1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStreetLine2() {
|
||||||
|
return streetLine2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStreetLine2(String streetLine2) {
|
||||||
|
this.streetLine2 = streetLine2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PostalArea getPostalArea() {
|
||||||
|
return postalArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPostalArea(PostalArea postalArea) {
|
||||||
|
this.postalArea = postalArea;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* 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.test.converter.caching;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.cache.CachingRegionFactory;
|
||||||
|
import org.hibernate.testing.cache.EntityRegionImpl;
|
||||||
|
import org.hibernate.testing.cache.ReadWriteEntityRegionAccessStrategy;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class BasicStructuredCachingOfConvertedValueTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-9615" )
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void basicCacheStructureTest() {
|
||||||
|
EntityPersister persister = sessionFactory().getMetamodel().entityPersisters().get( Address.class.getName() );
|
||||||
|
EntityRegionImpl region = (EntityRegionImpl) persister.getCacheAccessStrategy().getRegion();
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// test during store...
|
||||||
|
PostalAreaConverter.clearCounts();
|
||||||
|
|
||||||
|
Session session = openSession();
|
||||||
|
session.getTransaction().begin();
|
||||||
|
session.save( new Address( 1, "123 Main St.", null, PostalArea._78729 ) );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
{
|
||||||
|
final Object cachedItem = region.getDataMap().values().iterator().next();
|
||||||
|
final Map<String, ?> state = (Map) ( (ReadWriteEntityRegionAccessStrategy.Item) cachedItem ).getValue();
|
||||||
|
// this is the point of the Jira.. that this "should be" the converted value
|
||||||
|
assertThat( state.get( "postalArea" ), instanceOf( PostalArea.class ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat( PostalAreaConverter.toDatabaseCallCount, is(1) );
|
||||||
|
assertThat( PostalAreaConverter.toDomainCallCount, is(0) );
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// test during load...
|
||||||
|
PostalAreaConverter.clearCounts();
|
||||||
|
region.evictAll();
|
||||||
|
|
||||||
|
session = openSession();
|
||||||
|
session.getTransaction().begin();
|
||||||
|
Address address = session.get( Address.class, 1 );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
{
|
||||||
|
final Object cachedItem = region.getDataMap().values().iterator().next();
|
||||||
|
final Map<String, ?> state = (Map) ( (ReadWriteEntityRegionAccessStrategy.Item) cachedItem ).getValue();
|
||||||
|
// this is the point of the Jira.. that this "should be" the converted value
|
||||||
|
assertThat( state.get( "postalArea" ), instanceOf( PostalArea.class ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat( PostalAreaConverter.toDatabaseCallCount, is(0) );
|
||||||
|
assertThat( PostalAreaConverter.toDomainCallCount, is(1) );
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// cleanup
|
||||||
|
session = openSession();
|
||||||
|
session.getTransaction().begin();
|
||||||
|
session.delete( address );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addSettings(Map settings) {
|
||||||
|
super.addSettings( settings );
|
||||||
|
|
||||||
|
settings.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" );
|
||||||
|
settings.put( AvailableSettings.CACHE_REGION_FACTORY, CachingRegionFactory.class );
|
||||||
|
settings.put( AvailableSettings.USE_STRUCTURED_CACHE, "true" );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Address.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* 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.test.converter.caching;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.cache.spi.entry.StandardCacheEntryImpl;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.cache.CachingRegionFactory;
|
||||||
|
import org.hibernate.testing.cache.EntityRegionImpl;
|
||||||
|
import org.hibernate.testing.cache.ReadWriteEntityRegionAccessStrategy;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class BasicUnstructuredCachingOfConvertedValueTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
public static final int postalAreaAttributeIndex = 0;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-9615" )
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void basicCacheStructureTest() {
|
||||||
|
EntityPersister persister = sessionFactory().getMetamodel().entityPersisters().get( Address.class.getName() );
|
||||||
|
EntityRegionImpl region = (EntityRegionImpl) persister.getCacheAccessStrategy().getRegion();
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// test during store...
|
||||||
|
PostalAreaConverter.clearCounts();
|
||||||
|
|
||||||
|
Session session = openSession();
|
||||||
|
session.getTransaction().begin();
|
||||||
|
session.save( new Address( 1, "123 Main St.", null, PostalArea._78729 ) );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
{
|
||||||
|
final Object cachedItem = region.getDataMap().values().iterator().next();
|
||||||
|
final StandardCacheEntryImpl state = (StandardCacheEntryImpl) ( (ReadWriteEntityRegionAccessStrategy.Item) cachedItem ).getValue();
|
||||||
|
assertThat( state.getDisassembledState()[postalAreaAttributeIndex], instanceOf( PostalArea.class ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat( PostalAreaConverter.toDatabaseCallCount, is(1) );
|
||||||
|
assertThat( PostalAreaConverter.toDomainCallCount, is(0) );
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// test during load...
|
||||||
|
PostalAreaConverter.clearCounts();
|
||||||
|
region.evictAll();
|
||||||
|
|
||||||
|
session = openSession();
|
||||||
|
session.getTransaction().begin();
|
||||||
|
Address address = session.get( Address.class, 1 );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
{
|
||||||
|
final Object cachedItem = region.getDataMap().values().iterator().next();
|
||||||
|
final StandardCacheEntryImpl state = (StandardCacheEntryImpl) ( (ReadWriteEntityRegionAccessStrategy.Item) cachedItem ).getValue();
|
||||||
|
assertThat( state.getDisassembledState()[postalAreaAttributeIndex], instanceOf( PostalArea.class ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat( PostalAreaConverter.toDatabaseCallCount, is(0) );
|
||||||
|
assertThat( PostalAreaConverter.toDomainCallCount, is(1) );
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// cleanup
|
||||||
|
session = openSession();
|
||||||
|
session.getTransaction().begin();
|
||||||
|
session.delete( address );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addSettings(Map settings) {
|
||||||
|
super.addSettings( settings );
|
||||||
|
|
||||||
|
settings.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" );
|
||||||
|
settings.put( AvailableSettings.CACHE_REGION_FACTORY, CachingRegionFactory.class );
|
||||||
|
settings.put( AvailableSettings.USE_STRUCTURED_CACHE, "false" );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Address.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* 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.test.converter.caching;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
public enum PostalArea {
|
||||||
|
_78729( "78729", "North Austin", "Austin", State.TX );
|
||||||
|
|
||||||
|
private final String zipCode;
|
||||||
|
private final String name;
|
||||||
|
private final String cityName;
|
||||||
|
private final State state;
|
||||||
|
|
||||||
|
PostalArea(
|
||||||
|
String zipCode,
|
||||||
|
String name,
|
||||||
|
String cityName,
|
||||||
|
State state) {
|
||||||
|
this.zipCode = zipCode;
|
||||||
|
this.name = name;
|
||||||
|
this.cityName = cityName;
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PostalArea fromZipCode(String zipCode) {
|
||||||
|
if ( _78729.zipCode.equals( zipCode ) ) {
|
||||||
|
return _78729;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException( "Unknown zip code" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getZipCode() {
|
||||||
|
return zipCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCityName() {
|
||||||
|
return cityName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public State getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* 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.test.converter.caching;
|
||||||
|
|
||||||
|
import javax.persistence.AttributeConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class PostalAreaConverter
|
||||||
|
implements AttributeConverter<PostalArea, String> {
|
||||||
|
static int toDatabaseCallCount = 0;
|
||||||
|
static int toDomainCallCount = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convertToDatabaseColumn(PostalArea attribute) {
|
||||||
|
toDatabaseCallCount++;
|
||||||
|
if ( attribute == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return attribute.getZipCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PostalArea convertToEntityAttribute(String dbData) {
|
||||||
|
toDomainCallCount++;
|
||||||
|
if ( dbData == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return PostalArea.fromZipCode( dbData );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clearCounts() {
|
||||||
|
toDatabaseCallCount = 0;
|
||||||
|
toDomainCallCount = 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* 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.test.converter.caching;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
public enum State {
|
||||||
|
TX( "TX", "Texas" );
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
State(String code, String name) {
|
||||||
|
this.code = code;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* 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.test.converter.lob;
|
||||||
|
|
||||||
|
import javax.persistence.Cacheable;
|
||||||
|
import javax.persistence.Convert;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Lob;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Cache;
|
||||||
|
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Cacheable
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||||
|
public class Address {
|
||||||
|
@Id
|
||||||
|
Integer id;
|
||||||
|
String streetLine1;
|
||||||
|
String streetLine2;
|
||||||
|
@Lob
|
||||||
|
@Convert(converter = PostalAreaConverter.class)
|
||||||
|
PostalArea postalArea;
|
||||||
|
|
||||||
|
public Address() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address(
|
||||||
|
Integer id,
|
||||||
|
String streetLine1,
|
||||||
|
String streetLine2,
|
||||||
|
PostalArea postalArea) {
|
||||||
|
this.id = id;
|
||||||
|
this.streetLine1 = streetLine1;
|
||||||
|
this.streetLine2 = streetLine2;
|
||||||
|
this.postalArea = postalArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStreetLine1() {
|
||||||
|
return streetLine1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStreetLine1(String streetLine1) {
|
||||||
|
this.streetLine1 = streetLine1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStreetLine2() {
|
||||||
|
return streetLine2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStreetLine2(String streetLine2) {
|
||||||
|
this.streetLine2 = streetLine2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PostalArea getPostalArea() {
|
||||||
|
return postalArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPostalArea(PostalArea postalArea) {
|
||||||
|
this.postalArea = postalArea;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* 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.test.converter.lob;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ConverterAndLobTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-9615" )
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void basicTest() {
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// test during store...
|
||||||
|
PostalAreaConverter.clearCounts();
|
||||||
|
|
||||||
|
Session session = openSession();
|
||||||
|
session.getTransaction().begin();
|
||||||
|
session.save( new Address( 1, "123 Main St.", null, PostalArea._78729 ) );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
assertThat( PostalAreaConverter.toDatabaseCallCount, is(1) );
|
||||||
|
assertThat( PostalAreaConverter.toDomainCallCount, is(0) );
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// test during load...
|
||||||
|
PostalAreaConverter.clearCounts();
|
||||||
|
|
||||||
|
session = openSession();
|
||||||
|
session.getTransaction().begin();
|
||||||
|
Address address = session.get( Address.class, 1 );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
assertThat( PostalAreaConverter.toDatabaseCallCount, is(0) );
|
||||||
|
assertThat( PostalAreaConverter.toDomainCallCount, is(1) );
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// cleanup
|
||||||
|
session = openSession();
|
||||||
|
session.getTransaction().begin();
|
||||||
|
session.delete( address );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addSettings(Map settings) {
|
||||||
|
super.addSettings( settings );
|
||||||
|
settings.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Address.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* 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.test.converter.lob;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
public enum PostalArea {
|
||||||
|
_78729( "78729", "North Austin", "Austin", State.TX );
|
||||||
|
|
||||||
|
private final String zipCode;
|
||||||
|
private final String name;
|
||||||
|
private final String cityName;
|
||||||
|
private final State state;
|
||||||
|
|
||||||
|
PostalArea(
|
||||||
|
String zipCode,
|
||||||
|
String name,
|
||||||
|
String cityName,
|
||||||
|
State state) {
|
||||||
|
this.zipCode = zipCode;
|
||||||
|
this.name = name;
|
||||||
|
this.cityName = cityName;
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PostalArea fromZipCode(String zipCode) {
|
||||||
|
if ( _78729.zipCode.equals( zipCode ) ) {
|
||||||
|
return _78729;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException( "Unknown zip code" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getZipCode() {
|
||||||
|
return zipCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCityName() {
|
||||||
|
return cityName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public State getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* 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.test.converter.lob;
|
||||||
|
|
||||||
|
import javax.persistence.AttributeConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class PostalAreaConverter
|
||||||
|
implements AttributeConverter<PostalArea, String> {
|
||||||
|
static int toDatabaseCallCount = 0;
|
||||||
|
static int toDomainCallCount = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convertToDatabaseColumn(PostalArea attribute) {
|
||||||
|
toDatabaseCallCount++;
|
||||||
|
if ( attribute == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return attribute.getZipCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PostalArea convertToEntityAttribute(String dbData) {
|
||||||
|
toDomainCallCount++;
|
||||||
|
if ( dbData == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return PostalArea.fromZipCode( dbData );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clearCounts() {
|
||||||
|
toDatabaseCallCount = 0;
|
||||||
|
toDomainCallCount = 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* 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.test.converter.lob;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
public enum State {
|
||||||
|
TX( "TX", "Texas" );
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
State(String code, String name) {
|
||||||
|
this.code = code;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ import org.jboss.logging.Logger;
|
||||||
/**
|
/**
|
||||||
* @author Strong Liu
|
* @author Strong Liu
|
||||||
*/
|
*/
|
||||||
abstract class AbstractReadWriteAccessStrategy extends BaseRegionAccessStrategy {
|
public abstract class AbstractReadWriteAccessStrategy extends BaseRegionAccessStrategy {
|
||||||
private static final Logger LOG = Logger.getLogger( AbstractReadWriteAccessStrategy.class.getName() );
|
private static final Logger LOG = Logger.getLogger( AbstractReadWriteAccessStrategy.class.getName() );
|
||||||
|
|
||||||
private final UUID uuid = UUID.randomUUID();
|
private final UUID uuid = UUID.randomUUID();
|
||||||
|
@ -181,7 +181,7 @@ abstract class AbstractReadWriteAccessStrategy extends BaseRegionAccessStrategy
|
||||||
/**
|
/**
|
||||||
* Interface type implemented by all wrapper objects in the cache.
|
* Interface type implemented by all wrapper objects in the cache.
|
||||||
*/
|
*/
|
||||||
protected interface Lockable {
|
public interface Lockable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <code>true</code> if the enclosed value can be read by a transaction started at the given time.
|
* Returns <code>true</code> if the enclosed value can be read by a transaction started at the given time.
|
||||||
|
@ -214,7 +214,7 @@ abstract class AbstractReadWriteAccessStrategy extends BaseRegionAccessStrategy
|
||||||
/**
|
/**
|
||||||
* Wrapper type representing unlocked items.
|
* Wrapper type representing unlocked items.
|
||||||
*/
|
*/
|
||||||
protected final static class Item implements Serializable, Lockable {
|
public final static class Item implements Serializable, Lockable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private final Object value;
|
private final Object value;
|
||||||
|
@ -259,7 +259,7 @@ abstract class AbstractReadWriteAccessStrategy extends BaseRegionAccessStrategy
|
||||||
/**
|
/**
|
||||||
* Wrapper type representing locked items.
|
* Wrapper type representing locked items.
|
||||||
*/
|
*/
|
||||||
protected final static class Lock implements Serializable, Lockable, SoftLock {
|
public final static class Lock implements Serializable, Lockable, SoftLock {
|
||||||
|
|
||||||
private static final long serialVersionUID = 2L;
|
private static final long serialVersionUID = 2L;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import org.jboss.logging.Logger;
|
||||||
/**
|
/**
|
||||||
* @author Strong Liu
|
* @author Strong Liu
|
||||||
*/
|
*/
|
||||||
abstract class BaseRegionAccessStrategy implements RegionAccessStrategy {
|
public abstract class BaseRegionAccessStrategy implements RegionAccessStrategy {
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger( BaseRegionAccessStrategy.class );
|
private static final Logger LOG = Logger.getLogger( BaseRegionAccessStrategy.class );
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import org.hibernate.persister.entity.EntityPersister;
|
||||||
/**
|
/**
|
||||||
* @author Strong Liu
|
* @author Strong Liu
|
||||||
*/
|
*/
|
||||||
class ReadWriteEntityRegionAccessStrategy extends AbstractReadWriteAccessStrategy
|
public class ReadWriteEntityRegionAccessStrategy extends AbstractReadWriteAccessStrategy
|
||||||
implements EntityRegionAccessStrategy {
|
implements EntityRegionAccessStrategy {
|
||||||
private final EntityRegionImpl region;
|
private final EntityRegionImpl region;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue