All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.type.EnumType Maven / Gradle / Ivy

There is a newer version: 5.6.15.Final
Show newest version
/*
 * 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 .
 */
package org.hibernate.type;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Locale;
import java.util.Properties;
import jakarta.persistence.Enumerated;
import jakarta.persistence.MapKeyEnumerated;

import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.metamodel.model.convert.internal.NamedEnumValueConverter;
import org.hibernate.metamodel.model.convert.internal.OrdinalEnumValueConverter;
import org.hibernate.metamodel.model.convert.spi.EnumValueConverter;
import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.type.spi.TypeConfigurationAware;
import org.hibernate.usertype.DynamicParameterizedType;
import org.hibernate.usertype.EnhancedUserType;
import org.hibernate.usertype.LoggableUserType;

import org.jboss.logging.Logger;

/**
 * Value type mapper for enumerations.
 *
 * Generally speaking, the proper configuration is picked up from the annotations associated with the mapped attribute.
 *
 * There are a few configuration parameters understood by this type mapper:
    *
  • * enumClass - Names the enumeration class. *
  • *
  • * useNamed - Should enum be mapped via name. Default is to map as ordinal. Used when * annotations are not used (otherwise {@link jakarta.persistence.EnumType} is used). *
  • *
  • * type - Identifies the JDBC type (via type code) to be used for the column. *
  • *
* * @author Emmanuel Bernard * @author Hardy Ferentschik * @author Steve Ebersole */ @SuppressWarnings("unchecked") public class EnumType implements EnhancedUserType, DynamicParameterizedType, LoggableUserType, TypeConfigurationAware, Serializable { private static final Logger LOG = CoreLogging.logger( EnumType.class ); public static final String ENUM = "enumClass"; public static final String NAMED = "useNamed"; public static final String TYPE = "type"; private Class enumClass; private EnumValueConverter enumValueConverter; private TypeConfiguration typeConfiguration; @Override public void setParameterValues(Properties parameters) { // IMPL NOTE: we handle 2 distinct cases here: // 1) we are passed a ParameterType instance in the incoming Properties - generally // speaking this indicates the annotation-binding case, and the passed ParameterType // represents information about the attribute and annotation // 2) we are not passed a ParameterType - generally this indicates a hbm.xml binding case. final ParameterType reader = (ParameterType) parameters.get( PARAMETER_TYPE ); if ( reader != null ) { enumClass = reader.getReturnedClass().asSubclass( Enum.class ); final boolean isOrdinal; final jakarta.persistence.EnumType enumType = getEnumType( reader ); if ( enumType == null ) { isOrdinal = true; } else if ( jakarta.persistence.EnumType.ORDINAL.equals( enumType ) ) { isOrdinal = true; } else if ( jakarta.persistence.EnumType.STRING.equals( enumType ) ) { isOrdinal = false; } else { throw new AssertionFailure( "Unknown EnumType: " + enumType ); } final EnumJavaTypeDescriptor enumJavaDescriptor = (EnumJavaTypeDescriptor) typeConfiguration .getJavaTypeDescriptorRegistry() .getDescriptor( enumClass ); if ( isOrdinal ) { this.enumValueConverter = new OrdinalEnumValueConverter( enumJavaDescriptor ); } else { this.enumValueConverter = new NamedEnumValueConverter( enumJavaDescriptor ); } } else { final String enumClassName = (String) parameters.get( ENUM ); try { enumClass = ReflectHelper.classForName( enumClassName, this.getClass() ).asSubclass( Enum.class ); } catch ( ClassNotFoundException exception ) { throw new HibernateException( "Enum class not found: " + enumClassName, exception ); } this.enumValueConverter = interpretParameters( parameters ); } LOG.debugf( "Using %s-based conversion for Enum %s", isOrdinal() ? "ORDINAL" : "NAMED", enumClass.getName() ); } private jakarta.persistence.EnumType getEnumType(ParameterType reader) { jakarta.persistence.EnumType enumType = null; if ( reader.isPrimaryKey() ) { MapKeyEnumerated enumAnn = getAnnotation( reader.getAnnotationsMethod(), MapKeyEnumerated.class ); if ( enumAnn != null ) { enumType = enumAnn.value(); } } else { Enumerated enumAnn = getAnnotation( reader.getAnnotationsMethod(), Enumerated.class ); if ( enumAnn != null ) { enumType = enumAnn.value(); } } return enumType; } private A getAnnotation(Annotation[] annotations, Class anClass) { for ( Annotation annotation : annotations ) { if ( anClass.isInstance( annotation ) ) { return (A) annotation; } } return null; } private EnumValueConverter interpretParameters(Properties parameters) { final EnumJavaTypeDescriptor javaTypeDescriptor = (EnumJavaTypeDescriptor) typeConfiguration .getJavaTypeDescriptorRegistry() .getDescriptor( enumClass ); if ( parameters.containsKey( NAMED ) ) { final boolean useNamed = ConfigurationHelper.getBoolean( NAMED, parameters ); if ( useNamed ) { return new NamedEnumValueConverter( javaTypeDescriptor ); } else { return new OrdinalEnumValueConverter( javaTypeDescriptor ); } } if ( parameters.containsKey( TYPE ) ) { final int type = Integer.decode( (String) parameters.get( TYPE ) ); if ( isNumericType( type ) ) { return new OrdinalEnumValueConverter( javaTypeDescriptor ); } else if ( isCharacterType( type ) ) { return new NamedEnumValueConverter( javaTypeDescriptor ); } else { throw new HibernateException( String.format( Locale.ENGLISH, "Passed JDBC type code [%s] not recognized as numeric nor character", type ) ); } } // the fallback return new OrdinalEnumValueConverter( javaTypeDescriptor ); } private boolean isCharacterType(int jdbcTypeCode) { switch ( jdbcTypeCode ) { case Types.CHAR: case Types.LONGVARCHAR: case Types.VARCHAR: { return true; } default: { return false; } } } private boolean isNumericType(int jdbcTypeCode) { switch ( jdbcTypeCode ) { case Types.INTEGER: case Types.NUMERIC: case Types.SMALLINT: case Types.TINYINT: case Types.BIGINT: case Types.DECIMAL: case Types.DOUBLE: case Types.FLOAT: { return true; } default: return false; } } @Override public int[] sqlTypes() { verifyConfigured(); return new int[] { enumValueConverter.getJdbcTypeCode() }; } @Override public Class returnedClass() { return enumClass; } @Override public boolean equals(Object x, Object y) throws HibernateException { return x == y; } @Override public int hashCode(Object x) throws HibernateException { return x == null ? 0 : x.hashCode(); } @Override public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException { verifyConfigured(); return enumValueConverter.readValue( rs, names[0], session ); } private void verifyConfigured() { if ( enumValueConverter == null ) { throw new AssertionFailure( "EnumType (" + enumClass.getName() + ") not properly, fully configured" ); } } @Override public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException { verifyConfigured(); enumValueConverter.writeValue( st, (Enum) value, index, session ); } @Override public Object deepCopy(Object value) throws HibernateException { return value; } @Override public boolean isMutable() { return false; } @Override public Serializable disassemble(Object value) throws HibernateException { return ( Serializable ) value; } @Override public Object assemble(Serializable cached, Object owner) throws HibernateException { return cached; } @Override public Object replace(Object original, Object target, Object owner) throws HibernateException { return original; } @Override public TypeConfiguration getTypeConfiguration() { return typeConfiguration; } @Override public void setTypeConfiguration(TypeConfiguration typeConfiguration) { this.typeConfiguration = typeConfiguration; } @Override public String objectToSQLString(Object value) { verifyConfigured(); return enumValueConverter.toSqlLiteral( value ); } @Override public String toXMLString(Object value) { verifyConfigured(); return (String) enumValueConverter.getJavaDescriptor().unwrap( (Enum) value, String.class, null ); } @Override @SuppressWarnings("RedundantCast") public Object fromXMLString(String xmlValue) { verifyConfigured(); return (T) enumValueConverter.getJavaDescriptor().wrap( xmlValue, null ); } @Override public String toLoggableString(Object value, SessionFactoryImplementor factory) { verifyConfigured(); return enumValueConverter.getJavaDescriptor().toString( (Enum) value ); } public boolean isOrdinal() { verifyConfigured(); return enumValueConverter instanceof OrdinalEnumValueConverter; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy