NativeQuery support
- support for `#addScalar(Class,AttributeConverter)` - support for `#addScalar(Class,Class<AttributeConverter>)` - fixed problem with mapping of converted enums
This commit is contained in:
parent
3b210c493f
commit
2f8f04747b
|
@ -0,0 +1,20 @@
|
||||||
|
= Changes
|
||||||
|
|
||||||
|
Changes in 6.0 worth documenting in various places
|
||||||
|
|
||||||
|
|
||||||
|
== New features
|
||||||
|
|
||||||
|
Document in release-notes:
|
||||||
|
|
||||||
|
* `@SqlTypeCode`
|
||||||
|
* `@SqlType`
|
||||||
|
* `@JavaType`
|
||||||
|
* `NativeQuery#addScalar(Class)`
|
||||||
|
* `NativeQuery#addScalar(Class,AttributeConverter)`
|
||||||
|
* `NativeQuery#addScalar(Class,Class<AttributeConverter>)`
|
||||||
|
|
||||||
|
|
||||||
|
== Changes
|
||||||
|
|
||||||
|
Document in migration-guide.
|
|
@ -173,7 +173,7 @@ public class InferredBasicValueResolver {
|
||||||
|
|
||||||
switch ( enumStyle ) {
|
switch ( enumStyle ) {
|
||||||
case STRING: {
|
case STRING: {
|
||||||
final JavaTypeDescriptor<String> relationalJtd;
|
final JavaTypeDescriptor<?> relationalJtd;
|
||||||
if ( explicitJavaType != null ) {
|
if ( explicitJavaType != null ) {
|
||||||
if ( ! String.class.isAssignableFrom( explicitJavaType.getJavaType() ) ) {
|
if ( ! String.class.isAssignableFrom( explicitJavaType.getJavaType() ) ) {
|
||||||
throw new MappingException(
|
throw new MappingException(
|
||||||
|
@ -182,11 +182,12 @@ public class InferredBasicValueResolver {
|
||||||
" should handle `java.lang.String` as its relational type descriptor"
|
" should handle `java.lang.String` as its relational type descriptor"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
//noinspection unchecked
|
|
||||||
relationalJtd = explicitJavaType;
|
relationalJtd = explicitJavaType;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
relationalJtd = typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( String.class );
|
final boolean useCharacter = stdIndicators.getColumnLength() == 1;
|
||||||
|
final Class<?> relationalJavaType = useCharacter ? Character.class : String.class;
|
||||||
|
relationalJtd = typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( relationalJavaType );
|
||||||
}
|
}
|
||||||
|
|
||||||
final SqlTypeDescriptor std = explicitSqlType != null ? explicitSqlType : relationalJtd.getJdbcRecommendedSqlType( stdIndicators );
|
final SqlTypeDescriptor std = explicitSqlType != null ? explicitSqlType : relationalJtd.getJdbcRecommendedSqlType( stdIndicators );
|
||||||
|
|
|
@ -19,6 +19,8 @@ import org.hibernate.mapping.BasicValue;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
|
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
|
import org.hibernate.type.descriptor.ValueBinder;
|
||||||
|
import org.hibernate.type.descriptor.ValueExtractor;
|
||||||
import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter;
|
import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter;
|
||||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
@ -93,6 +95,7 @@ public class NamedConverterResolution<J> implements BasicValue.Resolution<J> {
|
||||||
final JavaTypeDescriptor explicitJtd = explicitJtdAccess != null
|
final JavaTypeDescriptor explicitJtd = explicitJtdAccess != null
|
||||||
? explicitJtdAccess.apply( typeConfiguration )
|
? explicitJtdAccess.apply( typeConfiguration )
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
final JavaTypeDescriptor domainJtd = explicitJtd != null
|
final JavaTypeDescriptor domainJtd = explicitJtd != null
|
||||||
? explicitJtd
|
? explicitJtd
|
||||||
: converter.getDomainJavaDescriptor();
|
: converter.getDomainJavaDescriptor();
|
||||||
|
@ -100,7 +103,9 @@ public class NamedConverterResolution<J> implements BasicValue.Resolution<J> {
|
||||||
final SqlTypeDescriptor explicitStd = explicitStdAccess != null
|
final SqlTypeDescriptor explicitStd = explicitStdAccess != null
|
||||||
? explicitStdAccess.apply( typeConfiguration )
|
? explicitStdAccess.apply( typeConfiguration )
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
final JavaTypeDescriptor relationalJtd = converter.getRelationalJavaDescriptor();
|
final JavaTypeDescriptor relationalJtd = converter.getRelationalJavaDescriptor();
|
||||||
|
|
||||||
final SqlTypeDescriptor relationalStd = explicitStd != null
|
final SqlTypeDescriptor relationalStd = explicitStd != null
|
||||||
? explicitStd
|
? explicitStd
|
||||||
: relationalJtd.getJdbcRecommendedSqlType( sqlTypeIndicators );
|
: relationalJtd.getJdbcRecommendedSqlType( sqlTypeIndicators );
|
||||||
|
@ -139,13 +144,46 @@ public class NamedConverterResolution<J> implements BasicValue.Resolution<J> {
|
||||||
SqlTypeDescriptor relationalStd,
|
SqlTypeDescriptor relationalStd,
|
||||||
JpaAttributeConverter valueConverter,
|
JpaAttributeConverter valueConverter,
|
||||||
MutabilityPlan mutabilityPlan) {
|
MutabilityPlan mutabilityPlan) {
|
||||||
|
assert domainJtd != null;
|
||||||
this.domainJtd = domainJtd;
|
this.domainJtd = domainJtd;
|
||||||
|
|
||||||
|
assert relationalJtd != null;
|
||||||
this.relationalJtd = relationalJtd;
|
this.relationalJtd = relationalJtd;
|
||||||
|
|
||||||
|
assert relationalStd != null;
|
||||||
this.relationalStd = relationalStd;
|
this.relationalStd = relationalStd;
|
||||||
|
|
||||||
|
assert valueConverter != null;
|
||||||
this.valueConverter = valueConverter;
|
this.valueConverter = valueConverter;
|
||||||
|
|
||||||
|
assert mutabilityPlan != null;
|
||||||
this.mutabilityPlan = mutabilityPlan;
|
this.mutabilityPlan = mutabilityPlan;
|
||||||
|
|
||||||
this.jdbcMapping = new StandardBasicTypeImpl( relationalJtd, relationalStd ).getJdbcMapping();
|
this.jdbcMapping = new JdbcMapping() {
|
||||||
|
private final ValueExtractor extractor = relationalStd.getExtractor( relationalJtd );
|
||||||
|
private final ValueBinder binder = relationalStd.getBinder( relationalJtd );
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JavaTypeDescriptor getJavaTypeDescriptor() {
|
||||||
|
return relationalJtd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqlTypeDescriptor getSqlTypeDescriptor() {
|
||||||
|
return relationalStd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueExtractor getJdbcValueExtractor() {
|
||||||
|
return extractor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueBinder getJdbcValueBinder() {
|
||||||
|
return binder;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// this.jdbcMapping = new StandardBasicTypeImpl( relationalJtd, relationalStd );
|
||||||
|
|
||||||
this.legacyResolvedType = new AttributeConverterTypeAdapter(
|
this.legacyResolvedType = new AttributeConverterTypeAdapter(
|
||||||
ConverterDescriptor.TYPE_NAME_PREFIX + valueConverter.getConverterJavaTypeDescriptor().getJavaType().getName(),
|
ConverterDescriptor.TYPE_NAME_PREFIX + valueConverter.getConverterJavaTypeDescriptor().getJavaType().getName(),
|
||||||
|
@ -156,8 +194,7 @@ public class NamedConverterResolution<J> implements BasicValue.Resolution<J> {
|
||||||
),
|
),
|
||||||
valueConverter,
|
valueConverter,
|
||||||
relationalStd,
|
relationalStd,
|
||||||
domainJtd.getJavaType(),
|
relationalJtd,
|
||||||
relationalJtd.getJavaType(),
|
|
||||||
domainJtd
|
domainJtd
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,6 +167,17 @@ public class BasicValue extends SimpleValue implements SqlTypeDescriptorIndicato
|
||||||
return column;
|
return column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getColumnLength() {
|
||||||
|
if ( column != null && column instanceof Column ) {
|
||||||
|
final Long length = ( (Column) column ).getLength();
|
||||||
|
return length == null ? NO_COLUMN_LENGTH : length;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return NO_COLUMN_LENGTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addColumn(Column incomingColumn) {
|
public void addColumn(Column incomingColumn) {
|
||||||
super.addColumn( incomingColumn );
|
super.addColumn( incomingColumn );
|
||||||
|
@ -330,7 +341,6 @@ public class BasicValue extends SimpleValue implements SqlTypeDescriptorIndicato
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JavaTypeDescriptor jtd = null;
|
JavaTypeDescriptor jtd = null;
|
||||||
|
|
||||||
// determine JTD if we can
|
// determine JTD if we can
|
||||||
|
|
|
@ -576,7 +576,7 @@ public abstract class SimpleValue implements KeyValue {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
final BasicJavaDescriptor entityAttributeJavaTypeDescriptor = (BasicJavaDescriptor) jpaAttributeConverter.getDomainJavaTypeDescriptor();
|
final BasicJavaDescriptor<?> domainJtd = (BasicJavaDescriptor<?>) jpaAttributeConverter.getDomainJavaTypeDescriptor();
|
||||||
|
|
||||||
|
|
||||||
// build the SqlTypeDescriptor adapter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// build the SqlTypeDescriptor adapter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -595,7 +595,7 @@ public abstract class SimpleValue implements KeyValue {
|
||||||
jdbcTypeCode = LobTypeMappings.getLobCodeTypeMapping( jdbcTypeCode );
|
jdbcTypeCode = LobTypeMappings.getLobCodeTypeMapping( jdbcTypeCode );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( Serializable.class.isAssignableFrom( entityAttributeJavaTypeDescriptor.getJavaType() ) ) {
|
if ( Serializable.class.isAssignableFrom( domainJtd.getJavaType() ) ) {
|
||||||
jdbcTypeCode = Types.BLOB;
|
jdbcTypeCode = Types.BLOB;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -642,19 +642,18 @@ public abstract class SimpleValue implements KeyValue {
|
||||||
jpaAttributeConverter.getDomainJavaTypeDescriptor().getJavaType().getSimpleName(),
|
jpaAttributeConverter.getDomainJavaTypeDescriptor().getJavaType().getSimpleName(),
|
||||||
jpaAttributeConverter.getRelationalJavaTypeDescriptor().getJavaType().getSimpleName()
|
jpaAttributeConverter.getRelationalJavaTypeDescriptor().getJavaType().getSimpleName()
|
||||||
);
|
);
|
||||||
return new AttributeConverterTypeAdapter(
|
return new AttributeConverterTypeAdapter<>(
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
jpaAttributeConverter,
|
jpaAttributeConverter,
|
||||||
sqlTypeDescriptorAdapter,
|
sqlTypeDescriptorAdapter,
|
||||||
jpaAttributeConverter.getDomainJavaTypeDescriptor().getJavaType(),
|
jpaAttributeConverter.getRelationalJavaTypeDescriptor(),
|
||||||
jpaAttributeConverter.getRelationalJavaTypeDescriptor().getJavaType(),
|
jpaAttributeConverter.getDomainJavaTypeDescriptor()
|
||||||
entityAttributeJavaTypeDescriptor
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTypeSpecified() {
|
public boolean isTypeSpecified() {
|
||||||
return typeName!=null;
|
return typeName != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTypeParameters(Properties parameterMap) {
|
public void setTypeParameters(Properties parameterMap) {
|
||||||
|
@ -752,11 +751,15 @@ public abstract class SimpleValue implements KeyValue {
|
||||||
|
|
||||||
private void createParameterImpl() {
|
private void createParameterImpl() {
|
||||||
try {
|
try {
|
||||||
String[] columnsNames = new String[columns.size()];
|
final String[] columnNames = new String[ columns.size() ];
|
||||||
|
final Long[] columnLengths = new Long[ columns.size() ];
|
||||||
|
|
||||||
for ( int i = 0; i < columns.size(); i++ ) {
|
for ( int i = 0; i < columns.size(); i++ ) {
|
||||||
Selectable column = columns.get(i);
|
final Selectable selectable = columns.get(i);
|
||||||
if (column instanceof Column){
|
if ( selectable instanceof Column ) {
|
||||||
columnsNames[i] = ((Column) column).getName();
|
final Column column = (Column) selectable;
|
||||||
|
columnNames[i] = column.getName();
|
||||||
|
columnLengths[i] = column.getLength();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,7 +784,8 @@ public abstract class SimpleValue implements KeyValue {
|
||||||
table.getSchema(),
|
table.getSchema(),
|
||||||
table.getName(),
|
table.getName(),
|
||||||
Boolean.valueOf( typeParameters.getProperty( DynamicParameterizedType.IS_PRIMARY_KEY ) ),
|
Boolean.valueOf( typeParameters.getProperty( DynamicParameterizedType.IS_PRIMARY_KEY ) ),
|
||||||
columnsNames
|
columnNames,
|
||||||
|
columnLengths
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -799,9 +803,17 @@ public abstract class SimpleValue implements KeyValue {
|
||||||
private final String table;
|
private final String table;
|
||||||
private final boolean primaryKey;
|
private final boolean primaryKey;
|
||||||
private final String[] columns;
|
private final String[] columns;
|
||||||
|
private final Long[] columnLengths;
|
||||||
|
|
||||||
private ParameterTypeImpl(Class returnedClass, Annotation[] annotationsMethod, String catalog, String schema,
|
private ParameterTypeImpl(
|
||||||
String table, boolean primaryKey, String[] columns) {
|
Class returnedClass,
|
||||||
|
Annotation[] annotationsMethod,
|
||||||
|
String catalog,
|
||||||
|
String schema,
|
||||||
|
String table,
|
||||||
|
boolean primaryKey,
|
||||||
|
String[] columns,
|
||||||
|
Long[] columnLengths) {
|
||||||
this.returnedClass = returnedClass;
|
this.returnedClass = returnedClass;
|
||||||
this.annotationsMethod = annotationsMethod;
|
this.annotationsMethod = annotationsMethod;
|
||||||
this.catalog = catalog;
|
this.catalog = catalog;
|
||||||
|
@ -809,6 +821,7 @@ public abstract class SimpleValue implements KeyValue {
|
||||||
this.table = table;
|
this.table = table;
|
||||||
this.primaryKey = primaryKey;
|
this.primaryKey = primaryKey;
|
||||||
this.columns = columns;
|
this.columns = columns;
|
||||||
|
this.columnLengths = columnLengths;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -845,5 +858,10 @@ public abstract class SimpleValue implements KeyValue {
|
||||||
public String[] getColumns() {
|
public String[] getColumns() {
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long[] getColumnLengths() {
|
||||||
|
return columnLengths;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.metamodel.model.convert;
|
||||||
|
|
||||||
|
import javax.persistence.AttributeConverter;
|
||||||
|
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.metamodel.model.convert.internal.JpaAttributeConverterImpl;
|
||||||
|
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||||
|
import org.hibernate.resource.beans.spi.ManagedBean;
|
||||||
|
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||||
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory for converter instances
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class Converters {
|
||||||
|
public static <O,R> BasicValueConverter<O,R> jpaAttributeConverter(
|
||||||
|
JavaTypeDescriptor<R> relationalJtd,
|
||||||
|
JavaTypeDescriptor<O> domainJtd,
|
||||||
|
Class<? extends AttributeConverter<O,R>> converterClass,
|
||||||
|
SessionFactory factory) {
|
||||||
|
final SessionFactoryImplementor sfi = (SessionFactoryImplementor) factory;
|
||||||
|
|
||||||
|
final ManagedBeanRegistry beanRegistry = sfi.getServiceRegistry().getService( ManagedBeanRegistry.class );
|
||||||
|
final ManagedBean<? extends AttributeConverter<O, R>> converterBean = beanRegistry.getBean( converterClass );
|
||||||
|
|
||||||
|
final TypeConfiguration typeConfiguration = sfi.getTypeConfiguration();
|
||||||
|
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
|
||||||
|
final JavaTypeDescriptor<? extends AttributeConverter<O, R>> converterJtd = jtdRegistry.getDescriptor( converterClass );
|
||||||
|
|
||||||
|
return new JpaAttributeConverterImpl<>( converterBean, converterJtd, domainJtd, relationalJtd );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Converters() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,14 +18,14 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class JpaAttributeConverterImpl<O,R> implements JpaAttributeConverter<O,R> {
|
public class JpaAttributeConverterImpl<O,R> implements JpaAttributeConverter<O,R> {
|
||||||
private final ManagedBean<AttributeConverter<O,R>> attributeConverterBean;
|
private final ManagedBean<? extends AttributeConverter<O,R>> attributeConverterBean;
|
||||||
private final JavaTypeDescriptor<AttributeConverter<O, R>> converterJavaTypeDescriptor;
|
private final JavaTypeDescriptor<? extends AttributeConverter<O, R>> converterJavaTypeDescriptor;
|
||||||
private final JavaTypeDescriptor<O> domainJavaTypeDescriptor;
|
private final JavaTypeDescriptor<O> domainJavaTypeDescriptor;
|
||||||
private final JavaTypeDescriptor<R> relationalJavaTypeDescriptor;
|
private final JavaTypeDescriptor<R> relationalJavaTypeDescriptor;
|
||||||
|
|
||||||
public JpaAttributeConverterImpl(
|
public JpaAttributeConverterImpl(
|
||||||
ManagedBean<AttributeConverter<O, R>> attributeConverterBean,
|
ManagedBean<? extends AttributeConverter<O, R>> attributeConverterBean,
|
||||||
JavaTypeDescriptor<AttributeConverter<O,R>> converterJavaTypeDescriptor,
|
JavaTypeDescriptor<? extends AttributeConverter<O,R>> converterJavaTypeDescriptor,
|
||||||
JavaTypeDescriptor<O> domainJavaTypeDescriptor,
|
JavaTypeDescriptor<O> domainJavaTypeDescriptor,
|
||||||
JavaTypeDescriptor<R> relationalJavaTypeDescriptor) {
|
JavaTypeDescriptor<R> relationalJavaTypeDescriptor) {
|
||||||
this.attributeConverterBean = attributeConverterBean;
|
this.attributeConverterBean = attributeConverterBean;
|
||||||
|
@ -35,7 +35,7 @@ public class JpaAttributeConverterImpl<O,R> implements JpaAttributeConverter<O,R
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ManagedBean<AttributeConverter<O, R>> getConverterBean() {
|
public ManagedBean<? extends AttributeConverter<O, R>> getConverterBean() {
|
||||||
return attributeConverterBean;
|
return attributeConverterBean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ public class JpaAttributeConverterImpl<O,R> implements JpaAttributeConverter<O,R
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JavaTypeDescriptor<AttributeConverter<O, R>> getConverterJavaTypeDescriptor() {
|
public JavaTypeDescriptor<? extends AttributeConverter<O, R>> getConverterJavaTypeDescriptor() {
|
||||||
return converterJavaTypeDescriptor;
|
return converterJavaTypeDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class NamedEnumValueConverter<E extends Enum<E>> implements EnumValueConv
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getJdbcTypeCode() {
|
public int getJdbcTypeCode() {
|
||||||
return Types.VARCHAR;
|
return sqlTypeDescriptor.getJdbcTypeCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,9 +17,9 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface JpaAttributeConverter<O,R> extends BasicValueConverter<O,R> {
|
public interface JpaAttributeConverter<O,R> extends BasicValueConverter<O,R> {
|
||||||
JavaTypeDescriptor<AttributeConverter<O,R>> getConverterJavaTypeDescriptor();
|
JavaTypeDescriptor<? extends AttributeConverter<O,R>> getConverterJavaTypeDescriptor();
|
||||||
|
|
||||||
ManagedBean<AttributeConverter<O,R>> getConverterBean();
|
ManagedBean<? extends AttributeConverter<O,R>> getConverterBean();
|
||||||
|
|
||||||
JavaTypeDescriptor<O> getDomainJavaTypeDescriptor();
|
JavaTypeDescriptor<O> getDomainJavaTypeDescriptor();
|
||||||
JavaTypeDescriptor<R> getRelationalJavaTypeDescriptor();
|
JavaTypeDescriptor<R> getRelationalJavaTypeDescriptor();
|
||||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Calendar;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import javax.persistence.AttributeConverter;
|
||||||
import javax.persistence.FlushModeType;
|
import javax.persistence.FlushModeType;
|
||||||
import javax.persistence.LockModeType;
|
import javax.persistence.LockModeType;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
|
@ -76,20 +77,6 @@ public interface NativeQuery<T> extends Query<T>, SynchronizeableQuery {
|
||||||
*/
|
*/
|
||||||
NativeQuery<T> addScalar(String columnAlias);
|
NativeQuery<T> addScalar(String columnAlias);
|
||||||
|
|
||||||
/**
|
|
||||||
* Declare a scalar query result.
|
|
||||||
* <p/>
|
|
||||||
* Functions like {@code <return-scalar/>} in {@code hbm.xml} or
|
|
||||||
* {@link javax.persistence.ColumnResult} in annotations
|
|
||||||
*
|
|
||||||
* @param columnAlias The column alias in the result-set to be processed
|
|
||||||
* as a scalar result
|
|
||||||
* @param type The Hibernate type as which to treat the value.
|
|
||||||
*
|
|
||||||
* @return {@code this}, for method chaining
|
|
||||||
*/
|
|
||||||
// NativeQuery<T> addScalar(String columnAlias, Type type);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Declare a scalar query result.
|
* Declare a scalar query result.
|
||||||
* <p/>
|
* <p/>
|
||||||
|
@ -105,12 +92,45 @@ public interface NativeQuery<T> extends Query<T>, SynchronizeableQuery {
|
||||||
NativeQuery<T> addScalar(String columnAlias, BasicDomainType type);
|
NativeQuery<T> addScalar(String columnAlias, BasicDomainType type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Declare a scalar query result with an explicit return type
|
* Declare a scalar query result using the specified result type.
|
||||||
|
*
|
||||||
|
* Hibernate will implicitly determine an appropriate conversion, if
|
||||||
|
* it can. Otherwise an exception will be thrown
|
||||||
*
|
*
|
||||||
* @return {@code this}, for method chaining
|
* @return {@code this}, for method chaining
|
||||||
|
*
|
||||||
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
NativeQuery<T> addScalar(String columnAlias, Class<?> javaType);
|
NativeQuery<T> addScalar(String columnAlias, Class<?> javaType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare a scalar query result with an explicit conversion
|
||||||
|
*
|
||||||
|
* @param relationalJavaType The Java type expected by the converter as its
|
||||||
|
* "relational" type.
|
||||||
|
* @param converter The conversion to apply. Consumes the JDBC value based
|
||||||
|
* on `relationalJavaType`.
|
||||||
|
*
|
||||||
|
* @return {@code this}, for method chaining
|
||||||
|
*
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
<C> NativeQuery<T> addScalar(String columnAlias, Class<C> relationalJavaType, AttributeConverter<?,C> converter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare a scalar query result with an explicit conversion
|
||||||
|
*
|
||||||
|
* @param relationalJavaType The Java type expected by the converter as its
|
||||||
|
* "relational" type.
|
||||||
|
* @param converter The conversion to apply. Consumes the JDBC value based
|
||||||
|
* on `relationalJavaType`.
|
||||||
|
*
|
||||||
|
* @return {@code this}, for method chaining
|
||||||
|
*
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
<C> NativeQuery<T> addScalar(String columnAlias, Class<C> relationalJavaType, Class<? extends AttributeConverter<?,C>> converter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new root return mapping, returning a {@link RootReturn} to allow
|
* Add a new root return mapping, returning a {@link RootReturn} to allow
|
||||||
* further definition.
|
* further definition.
|
||||||
|
|
|
@ -6,55 +6,62 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.results;
|
package org.hibernate.query.results;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import javax.persistence.AttributeConverter;
|
||||||
|
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
|
||||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class Builders {
|
public class Builders {
|
||||||
public static ScalarResultBuilder scalar(String columnAlias) {
|
public static ScalarResultBuilder scalar(String columnAlias) {
|
||||||
return new ScalarResultBuilder( columnAlias );
|
return new StandardScalarResultBuilder( columnAlias );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScalarResultBuilder scalar(
|
public static ScalarResultBuilder scalar(
|
||||||
String columnAlias,
|
String columnAlias,
|
||||||
BasicType<?> type) {
|
BasicType<?> type) {
|
||||||
return new ScalarResultBuilder( columnAlias, type );
|
return new StandardScalarResultBuilder( columnAlias, type );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScalarResultBuilder scalar(
|
public static ScalarResultBuilder scalar(
|
||||||
String columnAlias,
|
String columnAlias,
|
||||||
Class<?> javaType,
|
Class<?> javaType,
|
||||||
SessionFactoryImplementor factory) {
|
SessionFactoryImplementor factory) {
|
||||||
return new ScalarResultBuilder(
|
final JavaTypeDescriptor<?> javaTypeDescriptor = factory.getTypeConfiguration()
|
||||||
columnAlias,
|
.getJavaTypeDescriptorRegistry()
|
||||||
factory.getTypeConfiguration().standardBasicTypeForJavaType( javaType )
|
.getDescriptor( javaType );
|
||||||
);
|
|
||||||
|
return new StandardScalarResultBuilder( columnAlias, javaTypeDescriptor );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DomainResult<?> implicitScalarDomainResult(
|
public static <C> ResultBuilder scalar(
|
||||||
int colIndex,
|
String columnAlias,
|
||||||
String columnName,
|
Class<C> relationalJavaType,
|
||||||
JdbcValuesMetadata jdbcResultsMetadata,
|
AttributeConverter<?, C> converter,
|
||||||
Consumer<SqlSelection> sqlSelectionConsumer,
|
|
||||||
SessionFactoryImplementor sessionFactory) {
|
SessionFactoryImplementor sessionFactory) {
|
||||||
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
return ConvertedResultBuilder.from( columnAlias, relationalJavaType, converter, sessionFactory );
|
||||||
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( colIndex );
|
}
|
||||||
final BasicJavaDescriptor<?> javaTypeDescriptor = sqlTypeDescriptor.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
|
|
||||||
final BasicType<?> jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( javaTypeDescriptor, sqlTypeDescriptor );
|
public static <C> ResultBuilder scalar(
|
||||||
sqlSelectionConsumer.accept( new SqlSelectionImpl( colIndex, jdbcMapping ) );
|
String columnAlias,
|
||||||
return new BasicResult<>( colIndex, columnName, javaTypeDescriptor );
|
Class<C> relationalJavaType,
|
||||||
|
Class<? extends AttributeConverter<?, C>> converterJavaType,
|
||||||
|
SessionFactoryImplementor sessionFactory) {
|
||||||
|
return ConvertedResultBuilder.from( columnAlias, relationalJavaType, converterJavaType, sessionFactory );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScalarResultBuilder scalar(int position) {
|
||||||
|
// will be needed for interpreting legacy HBM <resultset/> mappings
|
||||||
|
throw new NotYetImplementedFor6Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScalarResultBuilder scalar(int position, BasicType<?> type) {
|
||||||
|
// will be needed for interpreting legacy HBM <resultset/> mappings
|
||||||
|
throw new NotYetImplementedFor6Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EntityResultBuilder entity(String tableAlias, String entityName) {
|
public static EntityResultBuilder entity(String tableAlias, String entityName) {
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
* 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.query.results;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import javax.persistence.AttributeConverter;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||||
|
import org.hibernate.resource.beans.spi.ManagedBean;
|
||||||
|
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||||
|
import org.hibernate.sql.ast.Clause;
|
||||||
|
import org.hibernate.sql.ast.SqlAstWalker;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
|
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||||
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||||
|
import org.hibernate.type.descriptor.ValueBinder;
|
||||||
|
import org.hibernate.type.descriptor.ValueExtractor;
|
||||||
|
import org.hibernate.type.descriptor.converter.ConvertedValueExtractor;
|
||||||
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
|
||||||
|
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ResultBuilder for explicitly converted scalar results
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ConvertedResultBuilder implements ScalarResultBuilder {
|
||||||
|
|
||||||
|
public static <C> ResultBuilder from(
|
||||||
|
String columnAlias,
|
||||||
|
Class<C> relationalJavaType,
|
||||||
|
AttributeConverter<?, C> converter,
|
||||||
|
SessionFactoryImplementor sessionFactory) {
|
||||||
|
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
||||||
|
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
|
||||||
|
final JavaTypeDescriptor<C> relationJtd = jtdRegistry.getDescriptor( relationalJavaType );
|
||||||
|
|
||||||
|
return new ConvertedResultBuilder( columnAlias, relationJtd, converter );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <C> ResultBuilder from(
|
||||||
|
String columnAlias,
|
||||||
|
Class<C> relationalJavaType,
|
||||||
|
Class<? extends AttributeConverter<?, C>> converterJavaType,
|
||||||
|
SessionFactoryImplementor sessionFactory) {
|
||||||
|
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
||||||
|
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
|
||||||
|
final JavaTypeDescriptor<C> relationJtd = jtdRegistry.getDescriptor( relationalJavaType );
|
||||||
|
|
||||||
|
final ManagedBeanRegistry beans = sessionFactory.getServiceRegistry().getService( ManagedBeanRegistry.class );
|
||||||
|
final ManagedBean<? extends AttributeConverter<?, C>> bean = beans.getBean( converterJavaType );
|
||||||
|
final AttributeConverter<?, C> converter = bean.getBeanInstance();
|
||||||
|
|
||||||
|
return new ConvertedResultBuilder( columnAlias, relationJtd, converter );
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String columnAlias;
|
||||||
|
private final JavaTypeDescriptor<?> relationJtd;
|
||||||
|
private final AttributeConverter<?,?> converter;
|
||||||
|
|
||||||
|
public ConvertedResultBuilder(
|
||||||
|
String columnAlias,
|
||||||
|
JavaTypeDescriptor<?> relationJtd,
|
||||||
|
AttributeConverter<?, ?> converter) {
|
||||||
|
assert columnAlias != null;
|
||||||
|
this.columnAlias = columnAlias;
|
||||||
|
|
||||||
|
assert relationJtd != null;
|
||||||
|
this.relationJtd = relationJtd;
|
||||||
|
|
||||||
|
assert converter != null;
|
||||||
|
this.converter = converter;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
@Override
|
||||||
|
public DomainResult<?> buildReturn(
|
||||||
|
JdbcValuesMetadata jdbcResultsMetadata,
|
||||||
|
BiFunction<String, String, LegacyFetchBuilder> legacyFetchResolver,
|
||||||
|
Consumer<SqlSelection> sqlSelectionConsumer,
|
||||||
|
SessionFactoryImplementor sessionFactory) {
|
||||||
|
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( columnAlias );
|
||||||
|
final int valuesArrayPosition = jdbcPosition - 1;
|
||||||
|
|
||||||
|
final SqlTypeDescriptor std = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
|
||||||
|
|
||||||
|
final ConverterMapping<Object> converterMapping = new ConverterMapping(
|
||||||
|
relationJtd,
|
||||||
|
std,
|
||||||
|
new ConvertedValueExtractor( std.getExtractor( relationJtd ), converter )
|
||||||
|
);
|
||||||
|
|
||||||
|
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, converterMapping );
|
||||||
|
sqlSelectionConsumer.accept( sqlSelection );
|
||||||
|
|
||||||
|
return new BasicResult( valuesArrayPosition, columnAlias, converterMapping.getJavaTypeDescriptor() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class ConverterMapping<T> implements MappingModelExpressable<T>, JdbcMapping {
|
||||||
|
private final JavaTypeDescriptor<T> jtd;
|
||||||
|
private final SqlTypeDescriptor std;
|
||||||
|
|
||||||
|
private final ValueExtractor<T> extractor;
|
||||||
|
|
||||||
|
public ConverterMapping(
|
||||||
|
JavaTypeDescriptor<T> jtd,
|
||||||
|
SqlTypeDescriptor std,
|
||||||
|
ValueExtractor<T> extractor) {
|
||||||
|
this.jtd = jtd;
|
||||||
|
this.std = std;
|
||||||
|
this.extractor = extractor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getJdbcTypeCount(TypeConfiguration typeConfiguration) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JavaTypeDescriptor<T> getJavaTypeDescriptor() {
|
||||||
|
return jtd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqlTypeDescriptor getSqlTypeDescriptor() {
|
||||||
|
return std;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueExtractor<T> getJdbcValueExtractor() {
|
||||||
|
return extractor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueBinder<?> getJdbcValueBinder() {
|
||||||
|
// this will never get used for binding values
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<JdbcMapping> getJdbcMappings(TypeConfiguration typeConfiguration) {
|
||||||
|
return Collections.singletonList( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitJdbcTypes(
|
||||||
|
Consumer<JdbcMapping> action,
|
||||||
|
Clause clause,
|
||||||
|
TypeConfiguration typeConfiguration) {
|
||||||
|
action.accept( this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private static class SqlSelectionImpl implements SqlSelection {
|
||||||
|
private final int valuesArrayPosition;
|
||||||
|
private final ConverterMapping converterMapping;
|
||||||
|
|
||||||
|
public SqlSelectionImpl(
|
||||||
|
int valuesArrayPosition,
|
||||||
|
ConverterMapping converterMapping) {
|
||||||
|
this.valuesArrayPosition = valuesArrayPosition;
|
||||||
|
this.converterMapping = converterMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getValuesArrayPosition() {
|
||||||
|
return valuesArrayPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueExtractor getJdbcValueExtractor() {
|
||||||
|
return converterMapping.getJdbcValueExtractor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MappingModelExpressable getExpressionType() {
|
||||||
|
return converterMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(SqlAstWalker sqlAstWalker) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,96 +6,10 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.results;
|
package org.hibernate.query.results;
|
||||||
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
|
||||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
|
||||||
import org.hibernate.type.BasicType;
|
|
||||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|
||||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see javax.persistence.ColumnResult
|
* Nominal extension to ResultBuilder for cases involving scalar results
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ScalarResultBuilder implements ResultBuilder {
|
public interface ScalarResultBuilder extends ResultBuilder {
|
||||||
private final String explicitName;
|
|
||||||
|
|
||||||
private final BasicType<?> explicitType;
|
|
||||||
private final JavaTypeDescriptor<?> explicitJavaTypeDescriptor;
|
|
||||||
|
|
||||||
ScalarResultBuilder(String explicitName, BasicType<?> explicitType) {
|
|
||||||
assert explicitName != null;
|
|
||||||
this.explicitName = explicitName;
|
|
||||||
|
|
||||||
assert explicitType != null;
|
|
||||||
this.explicitType = explicitType;
|
|
||||||
|
|
||||||
this.explicitJavaTypeDescriptor = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScalarResultBuilder(String explicitName, JavaTypeDescriptor<?> explicitJavaTypeDescriptor) {
|
|
||||||
assert explicitName != null;
|
|
||||||
this.explicitName = explicitName;
|
|
||||||
|
|
||||||
assert explicitJavaTypeDescriptor != null;
|
|
||||||
this.explicitJavaTypeDescriptor = explicitJavaTypeDescriptor;
|
|
||||||
|
|
||||||
this.explicitType = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScalarResultBuilder(String explicitName) {
|
|
||||||
assert explicitName != null;
|
|
||||||
this.explicitName = explicitName;
|
|
||||||
|
|
||||||
this.explicitType = null;
|
|
||||||
this.explicitJavaTypeDescriptor = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExplicitName() {
|
|
||||||
return explicitName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DomainResult<?> buildReturn(
|
|
||||||
JdbcValuesMetadata jdbcResultsMetadata,
|
|
||||||
BiFunction<String, String, LegacyFetchBuilder> legacyFetchResolver,
|
|
||||||
Consumer<SqlSelection> sqlSelectionConsumer,
|
|
||||||
SessionFactoryImplementor sessionFactory) {
|
|
||||||
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( explicitName );
|
|
||||||
final int valuesArrayPosition = jdbcPosition - 1;
|
|
||||||
|
|
||||||
final BasicType<?> jdbcMapping;
|
|
||||||
|
|
||||||
if ( explicitType != null ) {
|
|
||||||
jdbcMapping = explicitType;
|
|
||||||
}
|
|
||||||
else if ( explicitJavaTypeDescriptor != null ) {
|
|
||||||
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
|
||||||
|
|
||||||
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
|
|
||||||
|
|
||||||
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( explicitJavaTypeDescriptor, sqlTypeDescriptor );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
|
||||||
|
|
||||||
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
|
|
||||||
final JavaTypeDescriptor<?> javaTypeDescriptor = sqlTypeDescriptor.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
|
|
||||||
|
|
||||||
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( javaTypeDescriptor, sqlTypeDescriptor );
|
|
||||||
}
|
|
||||||
|
|
||||||
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, jdbcMapping );
|
|
||||||
sqlSelectionConsumer.accept( sqlSelection );
|
|
||||||
|
|
||||||
return new BasicResult( valuesArrayPosition, explicitName, jdbcMapping.getJavaTypeDescriptor() );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* 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.query.results;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
|
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||||
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||||
|
import org.hibernate.type.BasicType;
|
||||||
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see javax.persistence.ColumnResult
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class StandardScalarResultBuilder implements ScalarResultBuilder {
|
||||||
|
private final String explicitName;
|
||||||
|
|
||||||
|
private final BasicType<?> explicitType;
|
||||||
|
private final JavaTypeDescriptor<?> explicitJavaTypeDescriptor;
|
||||||
|
|
||||||
|
public StandardScalarResultBuilder(String explicitName) {
|
||||||
|
assert explicitName != null;
|
||||||
|
this.explicitName = explicitName;
|
||||||
|
|
||||||
|
this.explicitType = null;
|
||||||
|
this.explicitJavaTypeDescriptor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardScalarResultBuilder(String explicitName, BasicType<?> explicitType) {
|
||||||
|
assert explicitName != null;
|
||||||
|
this.explicitName = explicitName;
|
||||||
|
|
||||||
|
assert explicitType != null;
|
||||||
|
this.explicitType = explicitType;
|
||||||
|
|
||||||
|
this.explicitJavaTypeDescriptor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardScalarResultBuilder(String explicitName, JavaTypeDescriptor<?> explicitJavaTypeDescriptor) {
|
||||||
|
assert explicitName != null;
|
||||||
|
this.explicitName = explicitName;
|
||||||
|
|
||||||
|
assert explicitJavaTypeDescriptor != null;
|
||||||
|
this.explicitJavaTypeDescriptor = explicitJavaTypeDescriptor;
|
||||||
|
|
||||||
|
this.explicitType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardScalarResultBuilder(JavaTypeDescriptor<?> explicitJavaTypeDescriptor) {
|
||||||
|
assert explicitJavaTypeDescriptor != null;
|
||||||
|
this.explicitJavaTypeDescriptor = explicitJavaTypeDescriptor;
|
||||||
|
|
||||||
|
this.explicitName = null;
|
||||||
|
this.explicitType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExplicitName() {
|
||||||
|
return explicitName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DomainResult<?> buildReturn(
|
||||||
|
JdbcValuesMetadata jdbcResultsMetadata,
|
||||||
|
BiFunction<String, String, LegacyFetchBuilder> legacyFetchResolver,
|
||||||
|
Consumer<SqlSelection> sqlSelectionConsumer,
|
||||||
|
SessionFactoryImplementor sessionFactory) {
|
||||||
|
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( explicitName );
|
||||||
|
final int valuesArrayPosition = jdbcPosition - 1;
|
||||||
|
|
||||||
|
final BasicType<?> jdbcMapping;
|
||||||
|
|
||||||
|
if ( explicitType != null ) {
|
||||||
|
jdbcMapping = explicitType;
|
||||||
|
}
|
||||||
|
else if ( explicitJavaTypeDescriptor != null ) {
|
||||||
|
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
||||||
|
|
||||||
|
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
|
||||||
|
|
||||||
|
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( explicitJavaTypeDescriptor, sqlTypeDescriptor );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
||||||
|
|
||||||
|
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
|
||||||
|
final JavaTypeDescriptor<?> javaTypeDescriptor = sqlTypeDescriptor.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
|
||||||
|
|
||||||
|
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( javaTypeDescriptor, sqlTypeDescriptor );
|
||||||
|
}
|
||||||
|
|
||||||
|
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, jdbcMapping );
|
||||||
|
sqlSelectionConsumer.accept( sqlSelection );
|
||||||
|
|
||||||
|
return new BasicResult( valuesArrayPosition, explicitName, jdbcMapping.getJavaTypeDescriptor() );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import javax.persistence.AttributeConverter;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
import javax.persistence.FlushModeType;
|
import javax.persistence.FlushModeType;
|
||||||
|
@ -58,6 +59,7 @@ import org.hibernate.query.internal.QueryParameterBindingsImpl;
|
||||||
import org.hibernate.query.results.Builders;
|
import org.hibernate.query.results.Builders;
|
||||||
import org.hibernate.query.results.EntityResultBuilder;
|
import org.hibernate.query.results.EntityResultBuilder;
|
||||||
import org.hibernate.query.results.LegacyFetchBuilder;
|
import org.hibernate.query.results.LegacyFetchBuilder;
|
||||||
|
import org.hibernate.query.results.ResultBuilder;
|
||||||
import org.hibernate.query.results.ResultSetMappingImpl;
|
import org.hibernate.query.results.ResultSetMappingImpl;
|
||||||
import org.hibernate.query.spi.AbstractQuery;
|
import org.hibernate.query.spi.AbstractQuery;
|
||||||
import org.hibernate.query.spi.MutableQueryOptions;
|
import org.hibernate.query.spi.MutableQueryOptions;
|
||||||
|
@ -475,22 +477,41 @@ public class NativeQueryImpl<R>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NativeQueryImplementor<R> addScalar(String columnAlias) {
|
public NativeQueryImplementor<R> addScalar(String columnAlias) {
|
||||||
resultSetMapping.addResultBuilder( Builders.scalar( columnAlias ) );
|
return registerBuilder( Builders.scalar( columnAlias ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected NativeQueryImplementor<R> registerBuilder(ResultBuilder builder) {
|
||||||
|
resultSetMapping.addResultBuilder( builder );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NativeQueryImplementor<R> addScalar(String columnAlias, BasicDomainType type) {
|
public NativeQueryImplementor<R> addScalar(String columnAlias, BasicDomainType type) {
|
||||||
resultSetMapping.addResultBuilder( Builders.scalar( columnAlias, (BasicType<?>) type ) );
|
return registerBuilder( Builders.scalar( columnAlias, (BasicType<?>) type ) );
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NativeQueryImplementor<R> addScalar(String columnAlias, Class<?> javaType) {
|
public NativeQueryImplementor<R> addScalar(String columnAlias, Class<?> javaType) {
|
||||||
resultSetMapping.addResultBuilder( Builders.scalar( columnAlias, javaType, getSessionFactory() ) );
|
return registerBuilder( Builders.scalar( columnAlias, javaType, getSessionFactory() ) );
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <C> NativeQueryImplementor<R> addScalar(
|
||||||
|
String columnAlias,
|
||||||
|
Class<C> relationalJavaType,
|
||||||
|
AttributeConverter<?, C> converter) {
|
||||||
|
return registerBuilder( Builders.scalar( columnAlias, relationalJavaType, converter, getSessionFactory() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <C> NativeQueryImplementor<R> addScalar(
|
||||||
|
String columnAlias,
|
||||||
|
Class<C> relationalJavaType,
|
||||||
|
Class<? extends AttributeConverter<?, C>> converter) {
|
||||||
|
return registerBuilder( Builders.scalar( columnAlias, relationalJavaType, converter, getSessionFactory() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityResultBuilder addRoot(String tableAlias, String entityName) {
|
public EntityResultBuilder addRoot(String tableAlias, String entityName) {
|
||||||
final EntityResultBuilder resultBuilder = Builders.entity(
|
final EntityResultBuilder resultBuilder = Builders.entity(
|
||||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Calendar;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import javax.persistence.AttributeConverter;
|
||||||
import javax.persistence.FlushModeType;
|
import javax.persistence.FlushModeType;
|
||||||
import javax.persistence.LockModeType;
|
import javax.persistence.LockModeType;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
|
@ -58,6 +59,12 @@ public interface NativeQueryImplementor<R> extends QueryImplementor<R>, NativeQu
|
||||||
@Override
|
@Override
|
||||||
NativeQueryImplementor<R> addScalar(String columnAlias, Class<?> javaType);
|
NativeQueryImplementor<R> addScalar(String columnAlias, Class<?> javaType);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
<C> NativeQueryImplementor<R> addScalar(String columnAlias, Class<C> relationalJavaType, AttributeConverter<?,C> converter);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
<C> NativeQueryImplementor<R> addScalar(String columnAlias, Class<C> relationalJavaType, Class<? extends AttributeConverter<?,C>> converter);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
EntityResultBuilder addRoot(String tableAlias, String entityName);
|
EntityResultBuilder addRoot(String tableAlias, String entityName);
|
||||||
|
|
||||||
|
|
|
@ -306,7 +306,7 @@ public abstract class AbstractStandardBasicType<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
protected final void nullSafeSet(PreparedStatement st, Object value, int index, WrapperOptions options) throws SQLException {
|
protected void nullSafeSet(PreparedStatement st, Object value, int index, WrapperOptions options) throws SQLException {
|
||||||
remapSqlTypeDescriptor( options ).getBinder( javaTypeDescriptor ).bind( st, ( T ) value, index, options );
|
remapSqlTypeDescriptor( options ).getBinder( javaTypeDescriptor ).bind( st, ( T ) value, index, options );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,6 +430,16 @@ public abstract class AbstractStandardBasicType<T>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullSafeSet(
|
||||||
|
PreparedStatement st,
|
||||||
|
Object value,
|
||||||
|
int index,
|
||||||
|
boolean[] settable,
|
||||||
|
SharedSessionContractImplementor session) throws SQLException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void nullSafeSet(CallableStatement st, Object value, String name, SharedSessionContractImplementor session) throws SQLException {
|
public void nullSafeSet(CallableStatement st, Object value, String name, SharedSessionContractImplementor session) throws SQLException {
|
||||||
nullSafeSet( st, value, name, (WrapperOptions) session );
|
nullSafeSet( st, value, name, (WrapperOptions) session );
|
||||||
|
|
|
@ -64,7 +64,7 @@ import org.jboss.logging.Logger;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class EnumType<T extends Enum>
|
public class EnumType<T extends Enum<T>>
|
||||||
implements EnhancedUserType, DynamicParameterizedType, LoggableUserType, TypeConfigurationAware, Serializable {
|
implements EnhancedUserType, DynamicParameterizedType, LoggableUserType, TypeConfigurationAware, Serializable {
|
||||||
private static final Logger LOG = CoreLogging.logger( EnumType.class );
|
private static final Logger LOG = CoreLogging.logger( EnumType.class );
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ public class EnumType<T extends Enum>
|
||||||
|
|
||||||
private Class<T> enumClass;
|
private Class<T> enumClass;
|
||||||
|
|
||||||
private EnumValueConverter enumValueConverter;
|
private EnumValueConverter<T,?> enumValueConverter;
|
||||||
|
|
||||||
private TypeConfiguration typeConfiguration;
|
private TypeConfiguration typeConfiguration;
|
||||||
|
|
||||||
|
@ -106,6 +106,8 @@ public class EnumType<T extends Enum>
|
||||||
if ( reader != null ) {
|
if ( reader != null ) {
|
||||||
enumClass = reader.getReturnedClass().asSubclass( Enum.class );
|
enumClass = reader.getReturnedClass().asSubclass( Enum.class );
|
||||||
|
|
||||||
|
final Long columnLength = reader.getColumnLengths()[0];
|
||||||
|
|
||||||
final boolean isOrdinal;
|
final boolean isOrdinal;
|
||||||
final javax.persistence.EnumType enumType = getEnumType( reader );
|
final javax.persistence.EnumType enumType = getEnumType( reader );
|
||||||
if ( enumType == null ) {
|
if ( enumType == null ) {
|
||||||
|
@ -125,28 +127,31 @@ public class EnumType<T extends Enum>
|
||||||
.getJavaTypeDescriptorRegistry()
|
.getJavaTypeDescriptorRegistry()
|
||||||
.getDescriptor( enumClass );
|
.getDescriptor( enumClass );
|
||||||
|
|
||||||
final BasicJavaDescriptor<?> relationalJavaDescriptor = resolveRelationalJavaTypeDescriptor(
|
final LocalSqlTypeDescriptorIndicators indicators = new LocalSqlTypeDescriptorIndicators(
|
||||||
reader,
|
|
||||||
enumType,
|
enumType,
|
||||||
|
columnLength,
|
||||||
|
reader
|
||||||
|
);
|
||||||
|
|
||||||
|
final BasicJavaDescriptor<?> relationalJtd = resolveRelationalJavaTypeDescriptor(
|
||||||
|
indicators,
|
||||||
enumJavaDescriptor
|
enumJavaDescriptor
|
||||||
);
|
);
|
||||||
|
|
||||||
final SqlTypeDescriptor sqlTypeDescriptor = relationalJavaDescriptor.getJdbcRecommendedSqlType(
|
final SqlTypeDescriptor sqlTypeDescriptor = relationalJtd.getJdbcRecommendedSqlType( indicators );
|
||||||
new LocalSqlTypeDescriptorIndicators( enumType, reader )
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( isOrdinal ) {
|
if ( isOrdinal ) {
|
||||||
this.enumValueConverter = new OrdinalEnumValueConverter(
|
this.enumValueConverter = new OrdinalEnumValueConverter(
|
||||||
enumJavaDescriptor,
|
enumJavaDescriptor,
|
||||||
sqlTypeDescriptor,
|
sqlTypeDescriptor,
|
||||||
relationalJavaDescriptor
|
relationalJtd
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.enumValueConverter = new NamedEnumValueConverter(
|
this.enumValueConverter = new NamedEnumValueConverter(
|
||||||
enumJavaDescriptor,
|
enumJavaDescriptor,
|
||||||
sqlTypeDescriptor,
|
sqlTypeDescriptor,
|
||||||
relationalJavaDescriptor
|
relationalJtd
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,10 +177,9 @@ public class EnumType<T extends Enum>
|
||||||
}
|
}
|
||||||
|
|
||||||
private BasicJavaDescriptor<?> resolveRelationalJavaTypeDescriptor(
|
private BasicJavaDescriptor<?> resolveRelationalJavaTypeDescriptor(
|
||||||
ParameterType reader,
|
LocalSqlTypeDescriptorIndicators indicators,
|
||||||
javax.persistence.EnumType enumType, EnumJavaTypeDescriptor enumJavaDescriptor) {
|
EnumJavaTypeDescriptor<?> enumJavaDescriptor) {
|
||||||
return enumJavaDescriptor.getJdbcRecommendedSqlType( new LocalSqlTypeDescriptorIndicators( enumType, reader ) )
|
return enumJavaDescriptor.getJdbcRecommendedSqlType( indicators ).getJdbcRecommendedJavaTypeMapping( typeConfiguration );
|
||||||
.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private javax.persistence.EnumType getEnumType(ParameterType reader) {
|
private javax.persistence.EnumType getEnumType(ParameterType reader) {
|
||||||
|
@ -204,21 +208,26 @@ public class EnumType<T extends Enum>
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EnumValueConverter interpretParameters(Properties parameters) {
|
private EnumValueConverter<T,?> interpretParameters(Properties parameters) {
|
||||||
final EnumJavaTypeDescriptor enumJavaDescriptor = (EnumJavaTypeDescriptor) typeConfiguration
|
final EnumJavaTypeDescriptor<?> enumJavaDescriptor = (EnumJavaTypeDescriptor<?>) typeConfiguration
|
||||||
.getJavaTypeDescriptorRegistry()
|
.getJavaTypeDescriptorRegistry()
|
||||||
.getDescriptor( enumClass );
|
.getDescriptor( enumClass );
|
||||||
|
|
||||||
final ParameterType reader = (ParameterType) parameters.get( PARAMETER_TYPE );
|
final ParameterType reader = (ParameterType) parameters.get( PARAMETER_TYPE );
|
||||||
final javax.persistence.EnumType enumType = getEnumType( reader );
|
final javax.persistence.EnumType enumType = getEnumType( reader );
|
||||||
final LocalSqlTypeDescriptorIndicators localIndicators = new LocalSqlTypeDescriptorIndicators( enumType, reader );
|
|
||||||
|
|
||||||
final BasicJavaDescriptor stringJavaDescriptor = (BasicJavaDescriptor) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( String.class );
|
final LocalSqlTypeDescriptorIndicators localIndicators = new LocalSqlTypeDescriptorIndicators(
|
||||||
final BasicJavaDescriptor integerJavaDescriptor = (BasicJavaDescriptor) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Integer.class );
|
enumType,
|
||||||
|
reader.getColumnLengths()[0],
|
||||||
|
reader
|
||||||
|
);
|
||||||
|
final BasicJavaDescriptor<?> stringJavaDescriptor = (BasicJavaDescriptor<?>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( String.class );
|
||||||
|
final BasicJavaDescriptor<?> integerJavaDescriptor = (BasicJavaDescriptor<?>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Integer.class );
|
||||||
|
|
||||||
if ( parameters.containsKey( NAMED ) ) {
|
if ( parameters.containsKey( NAMED ) ) {
|
||||||
final boolean useNamed = ConfigurationHelper.getBoolean( NAMED, parameters );
|
final boolean useNamed = ConfigurationHelper.getBoolean( NAMED, parameters );
|
||||||
if ( useNamed ) {
|
if ( useNamed ) {
|
||||||
|
//noinspection rawtypes
|
||||||
return new NamedEnumValueConverter(
|
return new NamedEnumValueConverter(
|
||||||
enumJavaDescriptor,
|
enumJavaDescriptor,
|
||||||
stringJavaDescriptor.getJdbcRecommendedSqlType( localIndicators ),
|
stringJavaDescriptor.getJdbcRecommendedSqlType( localIndicators ),
|
||||||
|
@ -226,6 +235,7 @@ public class EnumType<T extends Enum>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
//noinspection rawtypes
|
||||||
return new OrdinalEnumValueConverter(
|
return new OrdinalEnumValueConverter(
|
||||||
enumJavaDescriptor,
|
enumJavaDescriptor,
|
||||||
integerJavaDescriptor.getJdbcRecommendedSqlType( localIndicators ),
|
integerJavaDescriptor.getJdbcRecommendedSqlType( localIndicators ),
|
||||||
|
@ -237,6 +247,7 @@ public class EnumType<T extends Enum>
|
||||||
if ( parameters.containsKey( TYPE ) ) {
|
if ( parameters.containsKey( TYPE ) ) {
|
||||||
final int type = Integer.decode( (String) parameters.get( TYPE ) );
|
final int type = Integer.decode( (String) parameters.get( TYPE ) );
|
||||||
if ( isNumericType( type ) ) {
|
if ( isNumericType( type ) ) {
|
||||||
|
//noinspection rawtypes
|
||||||
return new OrdinalEnumValueConverter(
|
return new OrdinalEnumValueConverter(
|
||||||
enumJavaDescriptor,
|
enumJavaDescriptor,
|
||||||
integerJavaDescriptor.getJdbcRecommendedSqlType( localIndicators ),
|
integerJavaDescriptor.getJdbcRecommendedSqlType( localIndicators ),
|
||||||
|
@ -244,6 +255,7 @@ public class EnumType<T extends Enum>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if ( isCharacterType( type ) ) {
|
else if ( isCharacterType( type ) ) {
|
||||||
|
//noinspection rawtypes
|
||||||
return new NamedEnumValueConverter(
|
return new NamedEnumValueConverter(
|
||||||
enumJavaDescriptor,
|
enumJavaDescriptor,
|
||||||
stringJavaDescriptor.getJdbcRecommendedSqlType( localIndicators ),
|
stringJavaDescriptor.getJdbcRecommendedSqlType( localIndicators ),
|
||||||
|
@ -336,7 +348,7 @@ public class EnumType<T extends Enum>
|
||||||
@Override
|
@Override
|
||||||
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
|
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
|
||||||
verifyConfigured();
|
verifyConfigured();
|
||||||
enumValueConverter.writeValue( st, (Enum) value, index, session );
|
enumValueConverter.writeValue( st, (T) value, index, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -383,7 +395,7 @@ public class EnumType<T extends Enum>
|
||||||
@Override
|
@Override
|
||||||
public String toXMLString(Object value) {
|
public String toXMLString(Object value) {
|
||||||
verifyConfigured();
|
verifyConfigured();
|
||||||
return (String) enumValueConverter.getDomainJavaDescriptor().unwrap( (Enum) value, String.class, null );
|
return enumValueConverter.getDomainJavaDescriptor().unwrap( (T) value, String.class, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -396,7 +408,7 @@ public class EnumType<T extends Enum>
|
||||||
@Override
|
@Override
|
||||||
public String toLoggableString(Object value, SessionFactoryImplementor factory) {
|
public String toLoggableString(Object value, SessionFactoryImplementor factory) {
|
||||||
verifyConfigured();
|
verifyConfigured();
|
||||||
return enumValueConverter.getDomainJavaDescriptor().toString( (Enum) value );
|
return enumValueConverter.getDomainJavaDescriptor().toString( (T) value );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOrdinal() {
|
public boolean isOrdinal() {
|
||||||
|
@ -406,10 +418,12 @@ public class EnumType<T extends Enum>
|
||||||
|
|
||||||
private class LocalSqlTypeDescriptorIndicators implements SqlTypeDescriptorIndicators {
|
private class LocalSqlTypeDescriptorIndicators implements SqlTypeDescriptorIndicators {
|
||||||
private final javax.persistence.EnumType enumType;
|
private final javax.persistence.EnumType enumType;
|
||||||
|
private final Long columnLength;
|
||||||
private final ParameterType reader;
|
private final ParameterType reader;
|
||||||
|
|
||||||
public LocalSqlTypeDescriptorIndicators(javax.persistence.EnumType enumType, ParameterType reader) {
|
public LocalSqlTypeDescriptorIndicators(javax.persistence.EnumType enumType, Long columnLength, ParameterType reader) {
|
||||||
this.enumType = enumType;
|
this.enumType = enumType;
|
||||||
|
this.columnLength = columnLength;
|
||||||
this.reader = reader;
|
this.reader = reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,5 +458,10 @@ public class EnumType<T extends Enum>
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getColumnLength() {
|
||||||
|
return columnLength == null ? NO_COLUMN_LENGTH : columnLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,17 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.type.descriptor.converter;
|
package org.hibernate.type.descriptor.converter;
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import javax.persistence.AttributeConverter;
|
||||||
|
|
||||||
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
|
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
|
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
|
||||||
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
|
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
|
||||||
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
|
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
|
||||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||||
|
@ -24,13 +32,14 @@ import org.jboss.logging.Logger;
|
||||||
public class AttributeConverterTypeAdapter<T> extends AbstractSingleColumnStandardBasicType<T> {
|
public class AttributeConverterTypeAdapter<T> extends AbstractSingleColumnStandardBasicType<T> {
|
||||||
private static final Logger log = Logger.getLogger( AttributeConverterTypeAdapter.class );
|
private static final Logger log = Logger.getLogger( AttributeConverterTypeAdapter.class );
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public static final String NAME_PREFIX = ConverterDescriptor.TYPE_NAME_PREFIX;
|
public static final String NAME_PREFIX = ConverterDescriptor.TYPE_NAME_PREFIX;
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final String description;
|
private final String description;
|
||||||
|
|
||||||
private final Class modelType;
|
private final JavaTypeDescriptor<T> domainJtd;
|
||||||
private final Class jdbcType;
|
private final JavaTypeDescriptor<?> relationalJtd;
|
||||||
private final JpaAttributeConverter<? extends T,?> attributeConverter;
|
private final JpaAttributeConverter<? extends T,?> attributeConverter;
|
||||||
|
|
||||||
private final MutabilityPlan<T> mutabilityPlan;
|
private final MutabilityPlan<T> mutabilityPlan;
|
||||||
|
@ -40,24 +49,22 @@ public class AttributeConverterTypeAdapter<T> extends AbstractSingleColumnStanda
|
||||||
String name,
|
String name,
|
||||||
String description,
|
String description,
|
||||||
JpaAttributeConverter<? extends T,?> attributeConverter,
|
JpaAttributeConverter<? extends T,?> attributeConverter,
|
||||||
SqlTypeDescriptor sqlTypeDescriptorAdapter,
|
SqlTypeDescriptor std,
|
||||||
Class modelType,
|
JavaTypeDescriptor<?> relationalJtd,
|
||||||
Class jdbcType,
|
JavaTypeDescriptor<T> domainJtd) {
|
||||||
JavaTypeDescriptor<T> entityAttributeJavaTypeDescriptor) {
|
//noinspection rawtypes
|
||||||
super( sqlTypeDescriptorAdapter, entityAttributeJavaTypeDescriptor );
|
super( std, (JavaTypeDescriptor) relationalJtd );
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.modelType = modelType;
|
this.domainJtd = domainJtd;
|
||||||
this.jdbcType = jdbcType;
|
this.relationalJtd = relationalJtd;
|
||||||
this.attributeConverter = attributeConverter;
|
this.attributeConverter = attributeConverter;
|
||||||
|
|
||||||
this.mutabilityPlan = entityAttributeJavaTypeDescriptor.getMutabilityPlan().isMutable()
|
this.mutabilityPlan = domainJtd.getMutabilityPlan().isMutable()
|
||||||
? new AttributeConverterMutabilityPlanImpl<>( attributeConverter )
|
? new AttributeConverterMutabilityPlanImpl<>( attributeConverter )
|
||||||
: ImmutableMutabilityPlan.INSTANCE;
|
: ImmutableMutabilityPlan.INSTANCE;
|
||||||
|
|
||||||
log.debugf( "Created AttributeConverterTypeAdapter -> %s", name );
|
log.debugf( "Created AttributeConverterTypeAdapter -> %s", name );
|
||||||
|
|
||||||
// throw new UnsupportedOperationException( );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -65,18 +72,42 @@ public class AttributeConverterTypeAdapter<T> extends AbstractSingleColumnStanda
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getModelType() {
|
public JavaTypeDescriptor<T> getDomainJtd() {
|
||||||
return modelType;
|
return domainJtd;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getJdbcType() {
|
public JavaTypeDescriptor<?> getRelationalJtd() {
|
||||||
return jdbcType;
|
return relationalJtd;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JpaAttributeConverter<? extends T,?> getAttributeConverter() {
|
public JpaAttributeConverter<? extends T,?> getAttributeConverter() {
|
||||||
return attributeConverter;
|
return attributeConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
public void nullSafeSet(
|
||||||
|
CallableStatement st,
|
||||||
|
Object value,
|
||||||
|
String name,
|
||||||
|
SharedSessionContractImplementor session) throws SQLException {
|
||||||
|
final AttributeConverter converter = attributeConverter.getConverterBean().getBeanInstance();
|
||||||
|
final Object converted = converter.convertToDatabaseColumn( value );
|
||||||
|
super.nullSafeSet( st, converted, name, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
protected void nullSafeSet(PreparedStatement st, Object value, int index, WrapperOptions options) throws SQLException {
|
||||||
|
final AttributeConverter converter = attributeConverter.getConverterBean().getBeanInstance();
|
||||||
|
final Object converted = converter.convertToDatabaseColumn( value );
|
||||||
|
super.nullSafeSet( st, converted, index, options );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MutabilityPlan<T> getMutabilityPlan() {
|
protected MutabilityPlan<T> getMutabilityPlan() {
|
||||||
return mutabilityPlan;
|
return mutabilityPlan;
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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.type.descriptor.converter;
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import javax.persistence.AttributeConverter;
|
||||||
|
import javax.persistence.PersistenceException;
|
||||||
|
|
||||||
|
import org.hibernate.type.descriptor.ValueExtractor;
|
||||||
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ConvertedValueExtractor<O,R> implements ValueExtractor<O> {
|
||||||
|
private static final Logger log = Logger.getLogger( ConvertedValueExtractor.class );
|
||||||
|
|
||||||
|
private final ValueExtractor<R> relationalExtractor;
|
||||||
|
private final AttributeConverter<O,R> converter;
|
||||||
|
|
||||||
|
public ConvertedValueExtractor(
|
||||||
|
ValueExtractor<R> relationalExtractor,
|
||||||
|
AttributeConverter<O, R> converter) {
|
||||||
|
this.relationalExtractor = relationalExtractor;
|
||||||
|
this.converter = converter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public O extract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
|
||||||
|
return doConversion( relationalExtractor.extract( rs, paramIndex, options ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public O extract(CallableStatement statement, int paramIndex, WrapperOptions options) throws SQLException {
|
||||||
|
return doConversion( relationalExtractor.extract( statement, paramIndex, options ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public O extract(CallableStatement statement, String paramName, WrapperOptions options) throws SQLException {
|
||||||
|
return doConversion( relationalExtractor.extract( statement, paramName, options ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private O doConversion(R extractedValue) {
|
||||||
|
try {
|
||||||
|
O convertedValue = converter.convertToEntityAttribute( extractedValue );
|
||||||
|
log.debugf( "Converted value on extraction: %s -> %s", extractedValue, convertedValue );
|
||||||
|
return convertedValue;
|
||||||
|
}
|
||||||
|
catch (PersistenceException pe) {
|
||||||
|
throw pe;
|
||||||
|
}
|
||||||
|
catch (RuntimeException re) {
|
||||||
|
throw new PersistenceException( "Error attempting to apply AttributeConverter", re );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,10 +5,15 @@
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.type.descriptor.java;
|
package org.hibernate.type.descriptor.java;
|
||||||
|
import java.sql.Types;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.type.descriptor.WrapperOptions;
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
import org.hibernate.type.descriptor.java.spi.Primitive;
|
import org.hibernate.type.descriptor.java.spi.Primitive;
|
||||||
|
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||||
|
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Descriptor for {@link Character} handling.
|
* Descriptor for {@link Character} handling.
|
||||||
|
@ -25,6 +30,7 @@ public class CharacterTypeDescriptor extends AbstractTypeDescriptor<Character> i
|
||||||
public String toString(Character value) {
|
public String toString(Character value) {
|
||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Character fromString(String string) {
|
public Character fromString(String string) {
|
||||||
if ( string.length() != 1 ) {
|
if ( string.length() != 1 ) {
|
||||||
|
|
|
@ -31,6 +31,12 @@ public class EnumJavaTypeDescriptor<T extends Enum<T>> extends AbstractTypeDescr
|
||||||
@Override
|
@Override
|
||||||
public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) {
|
public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) {
|
||||||
if ( context.getEnumeratedType() != null && context.getEnumeratedType() == EnumType.STRING ) {
|
if ( context.getEnumeratedType() != null && context.getEnumeratedType() == EnumType.STRING ) {
|
||||||
|
if ( context.getColumnLength() == 1 ) {
|
||||||
|
return context.isNationalized()
|
||||||
|
? context.getTypeConfiguration().getSqlTypeDescriptorRegistry().getDescriptor( Types.NCHAR )
|
||||||
|
: context.getTypeConfiguration().getSqlTypeDescriptorRegistry().getDescriptor( Types.CHAR );
|
||||||
|
}
|
||||||
|
|
||||||
return context.isNationalized()
|
return context.isNationalized()
|
||||||
? context.getTypeConfiguration().getSqlTypeDescriptorRegistry().getDescriptor( Types.NVARCHAR )
|
? context.getTypeConfiguration().getSqlTypeDescriptorRegistry().getDescriptor( Types.NVARCHAR )
|
||||||
: context.getTypeConfiguration().getSqlTypeDescriptorRegistry().getDescriptor( Types.VARCHAR );
|
: context.getTypeConfiguration().getSqlTypeDescriptorRegistry().getDescriptor( Types.VARCHAR );
|
||||||
|
|
|
@ -54,4 +54,9 @@ public class JavaTypeDescriptorBasicAdaptor<T> extends AbstractTypeDescriptor<T>
|
||||||
"Wrap strategy not known for this Java type : " + getJavaType().getName()
|
"Wrap strategy not known for this Java type : " + getJavaType().getName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "JavaTypeDescriptorBasicAdaptor(" + getJavaType().getName() + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
package org.hibernate.type.descriptor.sql;
|
package org.hibernate.type.descriptor.sql;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
|
|
||||||
|
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Descriptor for {@link Types#CHAR CHAR} handling.
|
* Descriptor for {@link Types#CHAR CHAR} handling.
|
||||||
*
|
*
|
||||||
|
@ -27,4 +30,9 @@ public class CharTypeDescriptor extends VarcharTypeDescriptor {
|
||||||
public int getSqlType() {
|
public int getSqlType() {
|
||||||
return Types.CHAR;
|
return Types.CHAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||||
|
return super.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ import org.hibernate.type.spi.TypeConfiguration;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface SqlTypeDescriptorIndicators {
|
public interface SqlTypeDescriptorIndicators {
|
||||||
|
int NO_COLUMN_LENGTH = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Was nationalized character datatype requested for the given Java type?
|
* Was nationalized character datatype requested for the given Java type?
|
||||||
*
|
*
|
||||||
|
@ -65,6 +67,13 @@ public interface SqlTypeDescriptorIndicators {
|
||||||
return Types.BOOLEAN;
|
return Types.BOOLEAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Useful for resolutions based on column length. E.g. choosing between a VARCHAR (String) and a CHAR(1) (Character/char)
|
||||||
|
*/
|
||||||
|
default long getColumnLength() {
|
||||||
|
return NO_COLUMN_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides access to the TypeConfiguration for access to various type-system registries.
|
* Provides access to the TypeConfiguration for access to various type-system registries.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -46,5 +46,6 @@ public interface DynamicParameterizedType extends ParameterizedType {
|
||||||
|
|
||||||
String[] getColumns();
|
String[] getColumns();
|
||||||
|
|
||||||
|
Long[] getColumnLengths();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,9 @@ package org.hibernate.orm.test.metamodel.mapping;
|
||||||
|
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
|
import javax.persistence.AttributeConverter;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Convert;
|
||||||
import javax.persistence.Embeddable;
|
import javax.persistence.Embeddable;
|
||||||
import javax.persistence.Embedded;
|
import javax.persistence.Embedded;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
@ -25,6 +28,7 @@ import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
import org.hibernate.metamodel.model.convert.internal.NamedEnumValueConverter;
|
import org.hibernate.metamodel.model.convert.internal.NamedEnumValueConverter;
|
||||||
import org.hibernate.metamodel.model.convert.internal.OrdinalEnumValueConverter;
|
import org.hibernate.metamodel.model.convert.internal.OrdinalEnumValueConverter;
|
||||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||||
|
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
import org.hibernate.testing.hamcrest.CollectionMatchers;
|
import org.hibernate.testing.hamcrest.CollectionMatchers;
|
||||||
|
@ -40,6 +44,7 @@ import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||||
|
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,9 +65,10 @@ public class SmokeTests {
|
||||||
.getEntityDescriptor( SimpleEntity.class );
|
.getEntityDescriptor( SimpleEntity.class );
|
||||||
|
|
||||||
final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping();
|
final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping();
|
||||||
assert Integer.class.equals( identifierMapping.getMappedTypeDescriptor()
|
assertThat(
|
||||||
.getMappedJavaTypeDescriptor()
|
identifierMapping.getMappedTypeDescriptor().getMappedJavaTypeDescriptor().getJavaType(),
|
||||||
.getJavaType() );
|
sameInstance( Integer.class )
|
||||||
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
final ModelPart namePart = entityDescriptor.findSubPart( "name" );
|
final ModelPart namePart = entityDescriptor.findSubPart( "name" );
|
||||||
|
@ -105,6 +111,23 @@ public class SmokeTests {
|
||||||
assertThat( attrMapping.getJdbcMapping().getSqlTypeDescriptor().getJdbcTypeCode(), is( Types.VARCHAR ) );
|
assertThat( attrMapping.getJdbcMapping().getSqlTypeDescriptor().getJdbcTypeCode(), is( Types.VARCHAR ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
final ModelPart part = entityDescriptor.findSubPart( "gender3" );
|
||||||
|
assert part instanceof BasicValuedSingularAttributeMapping;
|
||||||
|
final BasicValuedSingularAttributeMapping attrMapping = (BasicValuedSingularAttributeMapping) part;
|
||||||
|
assert "mapping_simple_entity".equals( attrMapping.getContainingTableExpression() );
|
||||||
|
assert "gender3".equals( attrMapping.getMappedColumnExpression() );
|
||||||
|
|
||||||
|
assertThat( attrMapping.getJavaTypeDescriptor().getJavaType(), equalTo( Gender.class ) );
|
||||||
|
|
||||||
|
final BasicValueConverter valueConverter = attrMapping.getValueConverter();
|
||||||
|
assertThat( valueConverter, instanceOf( JpaAttributeConverter.class ) );
|
||||||
|
assertThat( valueConverter.getDomainJavaDescriptor(), is( attrMapping.getJavaTypeDescriptor() ) );
|
||||||
|
assertThat( valueConverter.getRelationalJavaDescriptor().getJavaType(), equalTo( Character.class ) );
|
||||||
|
|
||||||
|
assertThat( attrMapping.getJdbcMapping().getSqlTypeDescriptor().getJdbcTypeCode(), is( Types.CHAR ) );
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
final ModelPart part = entityDescriptor.findSubPart( "component" );
|
final ModelPart part = entityDescriptor.findSubPart( "component" );
|
||||||
assert part instanceof EmbeddedAttributeMapping;
|
assert part instanceof EmbeddedAttributeMapping;
|
||||||
|
@ -223,6 +246,7 @@ public class SmokeTests {
|
||||||
private String name;
|
private String name;
|
||||||
private Gender gender;
|
private Gender gender;
|
||||||
private Gender gender2;
|
private Gender gender2;
|
||||||
|
private Gender gender3;
|
||||||
private Component component;
|
private Component component;
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
@ -260,6 +284,16 @@ public class SmokeTests {
|
||||||
this.gender2 = gender2;
|
this.gender2 = gender2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Convert( converter = GenderConverter.class )
|
||||||
|
@Column( length = 1 )
|
||||||
|
public Gender getGender3() {
|
||||||
|
return gender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGender3(Gender gender3) {
|
||||||
|
this.gender3 = gender3;
|
||||||
|
}
|
||||||
|
|
||||||
@Embedded
|
@Embedded
|
||||||
public Component getComponent() {
|
public Component getComponent() {
|
||||||
return component;
|
return component;
|
||||||
|
@ -270,6 +304,35 @@ public class SmokeTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class GenderConverter implements AttributeConverter<Gender,Character> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Character convertToDatabaseColumn(Gender attribute) {
|
||||||
|
if ( attribute == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( attribute == Gender.MALE ) {
|
||||||
|
return 'M';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'F';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Gender convertToEntityAttribute(Character dbData) {
|
||||||
|
if ( dbData == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( 'M' == dbData ) {
|
||||||
|
return Gender.MALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Gender.FEMALE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Embeddable
|
@Embeddable
|
||||||
static class SubComponent {
|
static class SubComponent {
|
||||||
private String subAttribute1;
|
private String subAttribute1;
|
||||||
|
|
|
@ -6,51 +6,70 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.orm.test.query.sql;
|
package org.hibernate.orm.test.query.sql;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.sql.Types;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.BasicValuedSingularAttributeMapping;
|
||||||
|
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||||
|
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
|
||||||
|
import org.hibernate.orm.test.metamodel.mapping.SmokeTests;
|
||||||
import org.hibernate.query.sql.spi.NativeQueryImplementor;
|
import org.hibernate.query.sql.spi.NativeQueryImplementor;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||||
import org.hibernate.testing.orm.domain.contacts.Contact;
|
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.hamcrest.CustomMatcher;
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@DomainModel(
|
@DomainModel(
|
||||||
standardModels = StandardDomainModel.CONTACTS
|
standardModels = StandardDomainModel.GAMBIT
|
||||||
)
|
)
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
public class NativeQueryScalarTests {
|
public class NativeQueryScalarTests {
|
||||||
|
public static final String STRING_VALUE = "a string value";
|
||||||
|
public static final String URL_STRING = "http://hibernate.org";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void fullyImplicitTest(SessionFactoryScope scope) {
|
public void fullyImplicitTest(SessionFactoryScope scope) {
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
final String sql = "select gender, first, last, id from contacts";
|
final String sql = "select theString, theInteger, id from EntityOfBasics";
|
||||||
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
||||||
|
|
||||||
final List<?> results = query.list();
|
final List<?> results = query.list();
|
||||||
assertThat( results.size(), is( 1 ) );
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
|
||||||
final Object result = results.get( 0 );
|
final Object result = results.get( 0 );
|
||||||
assertThat( result, instanceOf( Object[].class ) );
|
assertThat( result, instanceOf( Object[].class ) );
|
||||||
|
|
||||||
final Object[] values = (Object[]) result;
|
final Object[] values = (Object[]) result;
|
||||||
assertThat( values.length, is(4 ) );
|
assertThat( values.length, is(3 ) );
|
||||||
|
|
||||||
assertThat( ( (Number) values[0] ).intValue(), is( Contact.Gender.OTHER.ordinal() ) );
|
assertThat( values[ 0 ], is( STRING_VALUE ) );
|
||||||
assertThat( values[1], is( "My First" ) );
|
assertThat( values[ 1 ], is( 2 ) );
|
||||||
assertThat( values[2], is( "Contact" ) );
|
assertThat( values[ 2 ], is( 1 ) );
|
||||||
assertThat( values[3], is( 1 ) );
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -58,71 +77,192 @@ public class NativeQueryScalarTests {
|
||||||
public void explicitOrderTest(SessionFactoryScope scope) {
|
public void explicitOrderTest(SessionFactoryScope scope) {
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
final String sql = "select gender, first, last, id from contacts";
|
final String sql = "select theString, theInteger, id from EntityOfBasics";
|
||||||
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
||||||
// notice the reverse order from the select clause
|
// notice the reverse order from the select clause
|
||||||
query.addScalar( "id" );
|
query.addScalar( "id" );
|
||||||
query.addScalar( "last" );
|
query.addScalar( "theInteger" );
|
||||||
query.addScalar( "first" );
|
query.addScalar( "theString" );
|
||||||
query.addScalar( "gender" );
|
|
||||||
|
|
||||||
final List<?> results = query.list();
|
final List<?> results = query.list();
|
||||||
assertThat( results.size(), is( 1 ) );
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
|
||||||
final Object result = results.get( 0 );
|
final Object result = results.get( 0 );
|
||||||
assertThat( result, instanceOf( Object[].class ) );
|
assertThat( result, instanceOf( Object[].class ) );
|
||||||
|
|
||||||
final Object[] values = (Object[]) result;
|
final Object[] values = (Object[]) result;
|
||||||
assertThat( values.length, is(4 ) );
|
assertThat( values.length, is(3 ) );
|
||||||
|
|
||||||
assertThat( values[0], is( 1 ) );
|
assertThat( values[ 0 ], is( 1 ) );
|
||||||
assertThat( values[1], is( "Contact" ) );
|
assertThat( values[ 1 ], is( 2 ) );
|
||||||
assertThat( values[2], is( "My First" ) );
|
assertThat( values[ 2 ], is( STRING_VALUE ) );
|
||||||
assertThat( ( (Number) values[3] ).intValue(), is( Contact.Gender.OTHER.ordinal() ) );
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
// @FailureExpected( reason = "Explicit type support not working atm" )
|
|
||||||
public void explicitEnumTypeTest(SessionFactoryScope scope) {
|
public void explicitEnumTypeTest(SessionFactoryScope scope) {
|
||||||
|
final String sql = "select id, gender, ordinal_gender from EntityOfBasics";
|
||||||
|
|
||||||
|
// first, without explicit typing
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
final String sql = "select gender, first, last, id from contacts";
|
|
||||||
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
||||||
// notice the reverse order from the select clause
|
|
||||||
query.addScalar( "id" );
|
query.addScalar( "id" );
|
||||||
query.addScalar( "last" );
|
query.addScalar( "gender" );
|
||||||
query.addScalar( "first" );
|
query.addScalar( "ordinal_gender" );
|
||||||
query.addScalar( "gender", Contact.Gender.class );
|
|
||||||
|
|
||||||
final List<?> results = query.list();
|
final List<?> results = query.list();
|
||||||
assertThat( results.size(), is( 1 ) );
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
|
||||||
final Object result = results.get( 0 );
|
final Object result = results.get( 0 );
|
||||||
assertThat( result, instanceOf( Object[].class ) );
|
assertThat( result, instanceOf( Object[].class ) );
|
||||||
|
|
||||||
final Object[] values = (Object[]) result;
|
final Object[] values = (Object[]) result;
|
||||||
assertThat( values.length, is(4 ) );
|
assertThat( values.length, is(3 ) );
|
||||||
|
|
||||||
assertThat( values[0], is( 1 ) );
|
assertThat( values[ 0 ], is( 1 ) );
|
||||||
assertThat( values[1], is( "Contact" ) );
|
assertThat( values[ 1 ], is( "MALE" ) );
|
||||||
assertThat( values[2], is( "My First" ) );
|
assertThat( values[ 2 ], matchesOrdinal( EntityOfBasics.Gender.FEMALE ) );
|
||||||
assertThat( values[3], is( Contact.Gender.OTHER ) );
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// then using explicit typing
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
||||||
|
query.addScalar( "id" );
|
||||||
|
query.addScalar( "gender", EntityOfBasics.Gender.class );
|
||||||
|
query.addScalar( "ordinal_gender", EntityOfBasics.Gender.class );
|
||||||
|
|
||||||
|
final List<?> results = query.list();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
|
||||||
|
final Object result = results.get( 0 );
|
||||||
|
assertThat( result, instanceOf( Object[].class ) );
|
||||||
|
|
||||||
|
final Object[] values = (Object[]) result;
|
||||||
|
assertThat( values.length, is(3 ) );
|
||||||
|
|
||||||
|
assertThat( values[ 0 ], is( 1 ) );
|
||||||
|
assertThat( values[ 1 ], is( EntityOfBasics.Gender.MALE ) );
|
||||||
|
assertThat( values[ 2 ], is( EntityOfBasics.Gender.FEMALE ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void explicitConversionTest(SessionFactoryScope scope) {
|
||||||
|
final String sql = "select converted_gender from EntityOfBasics";
|
||||||
|
|
||||||
|
// Control
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
||||||
|
|
||||||
|
final List<?> results = query.list();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
|
||||||
|
final Object result = results.get( 0 );
|
||||||
|
assertThat( result, instanceOf( String.class ) );
|
||||||
|
|
||||||
|
assertThat( result, is( "O" ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Converter instance
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
||||||
|
query.addScalar(
|
||||||
|
"converted_gender",
|
||||||
|
Character.class,
|
||||||
|
new EntityOfBasics.GenderConverter()
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<?> results = query.list();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
|
||||||
|
final Object result = results.get( 0 );
|
||||||
|
assertThat( result, instanceOf( EntityOfBasics.Gender.class ) );
|
||||||
|
|
||||||
|
assertThat( result, is( EntityOfBasics.Gender.OTHER ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Converter class
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
||||||
|
query.addScalar(
|
||||||
|
"converted_gender",
|
||||||
|
Character.class,
|
||||||
|
EntityOfBasics.GenderConverter.class
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<?> results = query.list();
|
||||||
|
assertThat( results.size(), is( 1 ) );
|
||||||
|
|
||||||
|
final Object result = results.get( 0 );
|
||||||
|
assertThat( result, instanceOf( EntityOfBasics.Gender.class ) );
|
||||||
|
|
||||||
|
assertThat( result, is( EntityOfBasics.Gender.OTHER ) );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Matcher matchesOrdinal(Enum enumValue) {
|
||||||
|
return new CustomMatcher<Object>( "Enum ordinal value" ) {
|
||||||
|
@Override
|
||||||
|
public boolean matches(Object item) {
|
||||||
|
return ( (Number) item ).intValue() == enumValue.ordinal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public void verifyModel(SessionFactoryScope scope) {
|
||||||
|
final EntityMappingType entityDescriptor = scope.getSessionFactory()
|
||||||
|
.getRuntimeMetamodels()
|
||||||
|
.getEntityMappingType( EntityOfBasics.class );
|
||||||
|
|
||||||
|
final ModelPart part = entityDescriptor.findSubPart( "convertedGender", null );
|
||||||
|
assertThat( part, instanceOf( BasicValuedSingularAttributeMapping.class ) );
|
||||||
|
final BasicValuedSingularAttributeMapping attrMapping = (BasicValuedSingularAttributeMapping) part;
|
||||||
|
|
||||||
|
assertThat( attrMapping.getJavaTypeDescriptor().getJavaType(), equalTo( EntityOfBasics.Gender.class ) );
|
||||||
|
|
||||||
|
final BasicValueConverter valueConverter = attrMapping.getValueConverter();
|
||||||
|
assertThat( valueConverter, instanceOf( JpaAttributeConverter.class ) );
|
||||||
|
assertThat( valueConverter.getDomainJavaDescriptor(), is( attrMapping.getJavaTypeDescriptor() ) );
|
||||||
|
assertThat( valueConverter.getRelationalJavaDescriptor().getJavaType(), equalTo( Character.class ) );
|
||||||
|
|
||||||
|
assertThat( attrMapping.getJdbcMapping().getSqlTypeDescriptor().getJdbcTypeCode(), is( Types.CHAR ) );
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void prepareData(SessionFactoryScope scope) {
|
public void prepareData(SessionFactoryScope scope) throws MalformedURLException {
|
||||||
|
final URL url = new URL( URL_STRING );
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
session.persist(
|
final EntityOfBasics entityOfBasics = new EntityOfBasics( 1 );
|
||||||
new Contact(
|
entityOfBasics.setTheString( STRING_VALUE );
|
||||||
1,
|
entityOfBasics.setTheInteger( 2 );
|
||||||
new Contact.Name( "My First", "Contact"),
|
entityOfBasics.setGender( EntityOfBasics.Gender.MALE );
|
||||||
Contact.Gender.OTHER,
|
entityOfBasics.setOrdinalGender( EntityOfBasics.Gender.FEMALE );
|
||||||
LocalDate.of(1990,4,18)
|
entityOfBasics.setConvertedGender( EntityOfBasics.Gender.OTHER );
|
||||||
)
|
entityOfBasics.setTheUrl( url );
|
||||||
);
|
entityOfBasics.setTheInstant( Instant.EPOCH );
|
||||||
|
|
||||||
|
session.persist( entityOfBasics );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
final EntityOfBasics entity = session.get( EntityOfBasics.class, 1 );
|
||||||
|
assertThat( entity, notNullValue() );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -130,7 +270,7 @@ public class NativeQueryScalarTests {
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void cleanUpData(SessionFactoryScope scope) {
|
public void cleanUpData(SessionFactoryScope scope) {
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> session.createQuery( "delete Contact" ).executeUpdate()
|
session -> session.createQuery( "delete EntityOfBasics" ).executeUpdate()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.testing.orm.domain.gambit;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.sql.Clob;
|
import java.sql.Clob;
|
||||||
|
import java.sql.Types;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
@ -26,6 +27,8 @@ import javax.persistence.Id;
|
||||||
import javax.persistence.Temporal;
|
import javax.persistence.Temporal;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.SqlTypeCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
@ -34,7 +37,8 @@ public class EntityOfBasics {
|
||||||
|
|
||||||
public enum Gender {
|
public enum Gender {
|
||||||
MALE,
|
MALE,
|
||||||
FEMALE
|
FEMALE,
|
||||||
|
OTHER
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
@ -60,6 +64,13 @@ public class EntityOfBasics {
|
||||||
private ZonedDateTime theZonedDateTime;
|
private ZonedDateTime theZonedDateTime;
|
||||||
private OffsetDateTime theOffsetDateTime;
|
private OffsetDateTime theOffsetDateTime;
|
||||||
|
|
||||||
|
public EntityOfBasics() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityOfBasics(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
|
@ -127,7 +138,8 @@ public class EntityOfBasics {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Convert( converter = GenderConverter.class )
|
@Convert( converter = GenderConverter.class )
|
||||||
@Column(name = "converted_gender")
|
@Column(name = "converted_gender", length = 1)
|
||||||
|
@SqlTypeCode( Types.CHAR )
|
||||||
public Gender getConvertedGender() {
|
public Gender getConvertedGender() {
|
||||||
return convertedGender;
|
return convertedGender;
|
||||||
}
|
}
|
||||||
|
@ -244,6 +256,10 @@ public class EntityOfBasics {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( attribute == Gender.OTHER ) {
|
||||||
|
return 'O';
|
||||||
|
}
|
||||||
|
|
||||||
if ( attribute == Gender.MALE ) {
|
if ( attribute == Gender.MALE ) {
|
||||||
return 'M';
|
return 'M';
|
||||||
}
|
}
|
||||||
|
@ -257,6 +273,10 @@ public class EntityOfBasics {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( 'O' == dbData ) {
|
||||||
|
return Gender.OTHER;
|
||||||
|
}
|
||||||
|
|
||||||
if ( 'M' == dbData ) {
|
if ( 'M' == dbData ) {
|
||||||
return Gender.MALE;
|
return Gender.MALE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue