Search in sources :

Example 1 with JpaAttributeConverter

use of org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter in project hibernate-orm by hibernate.

the class SimpleValue method buildAttributeConverterTypeAdapter.

/**
 * Build a Hibernate Type that incorporates the JPA AttributeConverter.  AttributeConverter works totally in
 * memory, meaning it converts between one Java representation (the entity attribute representation) and another
 * (the value bound into JDBC statements or extracted from results).  However, the Hibernate Type system operates
 * at the lower level of actually dealing directly with those JDBC objects.  So even though we have an
 * AttributeConverter, we still need to "fill out" the rest of the BasicType data and bridge calls
 * to bind/extract through the converter.
 * <p/>
 * Essentially the idea here is that an intermediate Java type needs to be used.  Let's use an example as a means
 * to illustrate...  Consider an {@code AttributeConverter<Integer,String>}.  This tells Hibernate that the domain
 * model defines this attribute as an Integer value (the 'entityAttributeJavaType'), but that we need to treat the
 * value as a String (the 'databaseColumnJavaType') when dealing with JDBC (aka, the database type is a
 * VARCHAR/CHAR):<ul>
 *     <li>
 *         When binding values to PreparedStatements we need to convert the Integer value from the entity
 *         into a String and pass that String to setString.  The conversion is handled by calling
 *         {@link AttributeConverter#convertToDatabaseColumn(Object)}
 *     </li>
 *     <li>
 *         When extracting values from ResultSets (or CallableStatement parameters) we need to handle the
 *         value via getString, and convert that returned String to an Integer.  That conversion is handled
 *         by calling {@link AttributeConverter#convertToEntityAttribute(Object)}
 *     </li>
 * </ul>
 *
 * @return The built AttributeConverter -> Type adapter
 *
 * @todo : ultimately I want to see attributeConverterJavaType and attributeConverterJdbcTypeCode specify-able separately
 * then we can "play them against each other" in terms of determining proper typing
 *
 * @todo : see if we already have previously built a custom on-the-fly BasicType for this AttributeConverter; see note below about caching
 */
@SuppressWarnings("unchecked")
private Type buildAttributeConverterTypeAdapter() {
    // todo : validate the number of columns present here?
    final JpaAttributeConverter jpaAttributeConverter = attributeConverterDescriptor.createJpaAttributeConverter(new JpaAttributeConverterCreationContext() {

        @Override
        public ManagedBeanRegistry getManagedBeanRegistry() {
            return getMetadata().getMetadataBuildingOptions().getServiceRegistry().getService(ManagedBeanRegistry.class);
        }

        @Override
        public org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry getJavaTypeDescriptorRegistry() {
            return metadata.getTypeConfiguration().getJavaTypeDescriptorRegistry();
        }
    });
    final BasicJavaDescriptor entityAttributeJavaTypeDescriptor = jpaAttributeConverter.getDomainJavaTypeDescriptor();
    // build the SqlTypeDescriptor adapter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Going back to the illustration, this should be a SqlTypeDescriptor that handles the Integer <-> String
    // conversions.  This is the more complicated piece.  First we need to determine the JDBC type code
    // corresponding to the AttributeConverter's declared "databaseColumnJavaType" (how we read that value out
    // of ResultSets).  See JdbcTypeJavaClassMappings for details.  Again, given example, this should return
    // VARCHAR/CHAR
    final SqlTypeDescriptor recommendedSqlType = jpaAttributeConverter.getRelationalJavaTypeDescriptor().getJdbcRecommendedSqlType(// todo (6.0) : handle the other JdbcRecommendedSqlTypeMappingContext methods
    metadata::getTypeConfiguration);
    int jdbcTypeCode = recommendedSqlType.getSqlType();
    if (isLob()) {
        if (LobTypeMappings.INSTANCE.hasCorrespondingLobCode(jdbcTypeCode)) {
            jdbcTypeCode = LobTypeMappings.INSTANCE.getCorrespondingLobCode(jdbcTypeCode);
        } else {
            if (Serializable.class.isAssignableFrom(entityAttributeJavaTypeDescriptor.getJavaType())) {
                jdbcTypeCode = Types.BLOB;
            } else {
                throw new IllegalArgumentException(String.format(Locale.ROOT, "JDBC type-code [%s (%s)] not known to have a corresponding LOB equivalent, and Java type is not Serializable (to use BLOB)", jdbcTypeCode, JdbcTypeNameMapper.getTypeName(jdbcTypeCode)));
            }
        }
    }
    if (isNationalized()) {
        jdbcTypeCode = NationalizedTypeMappings.INSTANCE.getCorrespondingNationalizedCode(jdbcTypeCode);
    }
    // find the standard SqlTypeDescriptor for that JDBC type code (allow itr to be remapped if needed!)
    final SqlTypeDescriptor sqlTypeDescriptor = getMetadata().getMetadataBuildingOptions().getServiceRegistry().getService(JdbcServices.class).getJdbcEnvironment().getDialect().remapSqlTypeDescriptor(metadata.getTypeConfiguration().getSqlTypeDescriptorRegistry().getDescriptor(jdbcTypeCode));
    // and finally construct the adapter, which injects the AttributeConverter calls into the binding/extraction
    // process...
    final SqlTypeDescriptor sqlTypeDescriptorAdapter = new AttributeConverterSqlTypeDescriptorAdapter(jpaAttributeConverter, sqlTypeDescriptor, jpaAttributeConverter.getRelationalJavaTypeDescriptor());
    // todo : cache the AttributeConverterTypeAdapter in case that AttributeConverter is applied multiple times.
    final String name = AttributeConverterTypeAdapter.NAME_PREFIX + jpaAttributeConverter.getConverterJavaTypeDescriptor().getJavaType().getName();
    final String description = String.format("BasicType adapter for AttributeConverter<%s,%s>", jpaAttributeConverter.getDomainJavaTypeDescriptor().getJavaType().getSimpleName(), jpaAttributeConverter.getRelationalJavaTypeDescriptor().getJavaType().getSimpleName());
    return new AttributeConverterTypeAdapter(name, description, jpaAttributeConverter, sqlTypeDescriptorAdapter, jpaAttributeConverter.getDomainJavaTypeDescriptor().getJavaType(), jpaAttributeConverter.getRelationalJavaTypeDescriptor().getJavaType(), entityAttributeJavaTypeDescriptor);
}
Also used : AttributeConverterSqlTypeDescriptorAdapter(org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter) JdbcServices(org.hibernate.engine.jdbc.spi.JdbcServices) AttributeConverterTypeAdapter(org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter) BasicJavaDescriptor(org.hibernate.type.descriptor.java.BasicJavaDescriptor) JpaAttributeConverterCreationContext(org.hibernate.boot.model.convert.spi.JpaAttributeConverterCreationContext) SqlTypeDescriptor(org.hibernate.type.descriptor.sql.SqlTypeDescriptor) ManagedBeanRegistry(org.hibernate.resource.beans.spi.ManagedBeanRegistry) JpaAttributeConverter(org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter)

Example 2 with JpaAttributeConverter

use of org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter in project hibernate-orm by hibernate.

the class LiteralNode method determineConvertedValue.

@SuppressWarnings("unchecked")
protected String determineConvertedValue(AttributeConverterTypeAdapter converterTypeAdapter, Object literalValue) {
    if (getDataType().getReturnedClass().equals(converterTypeAdapter.getModelType())) {
        // apply the converter
        final JpaAttributeConverter converter = converterTypeAdapter.getAttributeConverter();
        final Object converted = converter.toRelationalValue(getLiteralValue());
        if (isCharacterData(converterTypeAdapter.sqlType())) {
            return "'" + converted.toString() + "'";
        } else {
            return converted.toString();
        }
    } else if (getDataType().getReturnedClass().equals(converterTypeAdapter.getJdbcType())) {
        if (isCharacterData(converterTypeAdapter.sqlType())) {
            return "'" + literalValue.toString() + "'";
        } else {
            return literalValue.toString();
        }
    } else {
        throw new QueryException(String.format(Locale.ROOT, "AttributeConverter domain-model attribute type [%s] and JDBC type [%s] did not match query literal type [%s]", converterTypeAdapter.getModelType().getName(), converterTypeAdapter.getJdbcType().getName(), getDataType().getReturnedClass().getName()));
    }
}
Also used : QueryException(org.hibernate.QueryException) JpaAttributeConverter(org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter)

Example 3 with JpaAttributeConverter

use of org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter in project hibernate-orm by hibernate.

the class GeometryConverterTest method testConverterUsage.

@Test
public void testConverterUsage() {
    try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().applySetting(AvailableSettings.DIALECT, GeoDBDialect.class).applySetting(AvailableSettings.HBM2DDL_AUTO, Action.CREATE_DROP).build()) {
        final MetadataSources metadataSources = new MetadataSources(ssr).addAnnotatedClass(GeometryConverter.class).addAnnotatedClass(MyEntity.class);
        final MetadataBuilderImplementor metadataBuilder = (MetadataBuilderImplementor) metadataSources.getMetadataBuilder();
        try (final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) metadataBuilder.build().buildSessionFactory()) {
            final TypeConfiguration typeConfiguration = sessionFactory.getMetamodel().getTypeConfiguration();
            assertThat(typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor(Geometry.class), sameInstance(GeolatteGeometryJavaTypeDescriptor.INSTANCE));
            // todo (5.3) : what to assert wrt to SqlTypeDescriptor?  Anything?
            final EntityPersister entityPersister = sessionFactory.getMetamodel().entityPersister(MyEntity.class);
            final AttributeConverterTypeAdapter geometryAttributeType = assertTyping(AttributeConverterTypeAdapter.class, entityPersister.getPropertyType("geometry"));
            final JpaAttributeConverter converter = assertTyping(JpaAttributeConverter.class, geometryAttributeType.getAttributeConverter());
            assert GeometryConverter.class.equals(converter.getConverterBean().getBeanClass());
        }
    }
}
Also used : MetadataBuilderImplementor(org.hibernate.boot.spi.MetadataBuilderImplementor) Geometry(org.geolatte.geom.Geometry) EntityPersister(org.hibernate.persister.entity.EntityPersister) StandardServiceRegistryBuilder(org.hibernate.boot.registry.StandardServiceRegistryBuilder) SessionFactoryImplementor(org.hibernate.engine.spi.SessionFactoryImplementor) JpaAttributeConverter(org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter) MetadataSources(org.hibernate.boot.MetadataSources) AttributeConverterTypeAdapter(org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter) TypeConfiguration(org.hibernate.type.spi.TypeConfiguration) StandardServiceRegistry(org.hibernate.boot.registry.StandardServiceRegistry) Test(org.junit.Test)

Aggregations

JpaAttributeConverter (org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter)3 AttributeConverterTypeAdapter (org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter)2 Geometry (org.geolatte.geom.Geometry)1 QueryException (org.hibernate.QueryException)1 MetadataSources (org.hibernate.boot.MetadataSources)1 JpaAttributeConverterCreationContext (org.hibernate.boot.model.convert.spi.JpaAttributeConverterCreationContext)1 StandardServiceRegistry (org.hibernate.boot.registry.StandardServiceRegistry)1 StandardServiceRegistryBuilder (org.hibernate.boot.registry.StandardServiceRegistryBuilder)1 MetadataBuilderImplementor (org.hibernate.boot.spi.MetadataBuilderImplementor)1 JdbcServices (org.hibernate.engine.jdbc.spi.JdbcServices)1 SessionFactoryImplementor (org.hibernate.engine.spi.SessionFactoryImplementor)1 EntityPersister (org.hibernate.persister.entity.EntityPersister)1 ManagedBeanRegistry (org.hibernate.resource.beans.spi.ManagedBeanRegistry)1 AttributeConverterSqlTypeDescriptorAdapter (org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter)1 BasicJavaDescriptor (org.hibernate.type.descriptor.java.BasicJavaDescriptor)1 SqlTypeDescriptor (org.hibernate.type.descriptor.sql.SqlTypeDescriptor)1 TypeConfiguration (org.hibernate.type.spi.TypeConfiguration)1 Test (org.junit.Test)1