HHH-14408 Test that user type provided by integrator is properly registered

This commit is contained in:
Christian Beikov 2021-02-03 13:32:59 +01:00
parent d213d675ce
commit 6fcb83c90d
5 changed files with 305 additions and 1 deletions

View File

@ -0,0 +1,120 @@
/*
* 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.usertype;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.Enumeration;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.internal.util.ConfigHelper;
import org.hibernate.type.CustomType;
import org.hibernate.type.Type;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Christian Beikov
*/
public class IntegratorProvidedUserTypeTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {
StringWrapperTestEntity.class
};
}
protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) {
builder.applyClassLoader( new TestClassLoader() );
}
@Test
@TestForIssue( jiraKey = "HHH-14408" )
public void test() {
Type type = sessionFactory().getMetamodel().entityPersister( StringWrapperTestEntity.class )
.getPropertyType( "stringWrapper" );
Assert.assertTrue( "Type was initialized too early i.e. before integrators were run", type instanceof CustomType );
}
@Entity
public static class StringWrapperTestEntity implements Serializable {
@Id
private Integer id;
private StringWrapper stringWrapper;
}
private static class TestClassLoader extends ClassLoader {
/**
* testStoppableClassLoaderService() needs a custom JDK service implementation. Rather than using a real one
* on the test classpath, force it in here.
*/
@Override
protected Enumeration<URL> findResources(String name) throws IOException {
if (name.equals( "META-INF/services/org.hibernate.integrator.spi.Integrator" )) {
final URL serviceUrl = ConfigHelper.findAsResource(
"org/hibernate/test/service/org.hibernate.integrator.spi.Integrator" );
return new Enumeration<URL>() {
boolean hasMore = true;
@Override
public boolean hasMoreElements() {
return hasMore;
}
@Override
public URL nextElement() {
hasMore = false;
return serviceUrl;
}
};
}
else {
return java.util.Collections.enumeration( java.util.Collections.<URL>emptyList() );
}
}
/**
* Reloading class from binary file.
*
* @param originalClass Original class.
* @throws IOException .
*/
public void overrideClass(final Class<?> originalClass) throws IOException {
String originalPath = "/" + originalClass.getName().replaceAll("\\.", "/") + ".class";
InputStream inputStream = originalClass.getResourceAsStream( originalPath);
Assert.assertNotNull(inputStream);
try {
byte[] data = toByteArray( inputStream );
defineClass(originalClass.getName(), data, 0, data.length);
} finally {
inputStream.close();
}
}
private byte[] toByteArray(InputStream inputStream) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int read;
byte[] slice = new byte[2000];
while ( (read = inputStream.read(slice, 0, slice.length) ) != -1) {
out.write( slice, 0, read );
}
out.flush();
return out.toByteArray();
}
}
}

View File

@ -0,0 +1,38 @@
package org.hibernate.test.usertype;
import java.io.Serializable;
/**
* @author Christian Beikov
*/
public class StringWrapper implements Serializable {
private final String value;
public StringWrapper(String value) {
this.value = value;
}
public String getValue() {
return value;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
StringWrapper that = (StringWrapper) o;
return value.equals( that.value );
}
@Override
public int hashCode() {
return value.hashCode();
}
}

View File

@ -0,0 +1,112 @@
package org.hibernate.test.usertype;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Objects;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.StringType;
import org.hibernate.usertype.UserType;
import org.jboss.logging.Logger;
/**
* @author Christian Beikov
*/
public class StringWrapperUserType implements UserType {
public static final StringWrapperUserType INSTANCE = new StringWrapperUserType();
private static final Logger log = Logger.getLogger( StringWrapperUserType.class );
@Override
public int[] sqlTypes() {
return new int[] {StringType.INSTANCE.sqlType()};
}
@Override
public Class returnedClass() {
return StringWrapper.class;
}
@Override
public boolean equals(Object x, Object y)
throws HibernateException {
return Objects.equals( x, y );
}
@Override
public int hashCode(Object x)
throws HibernateException {
return Objects.hashCode( x );
}
@Override
public Object nullSafeGet(
ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
String columnName = names[0];
String columnValue = (String) rs.getObject( columnName );
log.debugv("Result set column {0} value is {1}", columnName, columnValue);
return columnValue == null ? null :
fromString( columnValue );
}
@Override
public void nullSafeSet(
PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
if ( value == null ) {
log.debugv("Binding null to parameter {0} ",index);
st.setNull( index, Types.VARCHAR );
}
else {
String stringValue = toString( (StringWrapper) value );
log.debugv("Binding {0} to parameter {1} ", stringValue, index);
st.setString( index, stringValue );
}
}
public String toString(StringWrapper value) {
return value.getValue();
}
public StringWrapper fromString(String string) {
if ( string == null || string.isEmpty() ) {
return null;
}
return new StringWrapper( string );
}
@Override
public Object deepCopy(Object value)
throws HibernateException {
return value;
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Serializable disassemble(Object value)
throws HibernateException {
return (StringWrapper) deepCopy( value );
}
@Override
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return deepCopy( cached );
}
@Override
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return deepCopy( original );
}
}

View File

@ -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.usertype;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
/**
* @author Christian Beikov
*/
public class StringWrapperUserTypeIntegrator implements Integrator {
@Override
public void integrate(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
MetadataImplementor mi = (MetadataImplementor) metadata;
mi.getTypeResolver().registerTypeOverride( StringWrapperUserType.INSTANCE, new String[] { StringWrapperUserType.INSTANCE.returnedClass().getName()});
}
@Override
public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
}
}

View File

@ -1 +1,2 @@
org.hibernate.test.service.TestIntegrator
org.hibernate.test.usertype.StringWrapperUserTypeIntegrator