HHH-9524 - Make strategy for interpreting id-generator annotations pluggable
This commit is contained in:
parent
64c3e4c783
commit
1f50efa34c
|
@ -23,7 +23,6 @@
|
|||
*/
|
||||
package org.hibernate.boot;
|
||||
|
||||
import java.util.List;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.SharedCacheMode;
|
||||
|
||||
|
@ -32,7 +31,7 @@ import org.hibernate.boot.archive.scan.spi.ScanEnvironment;
|
|||
import org.hibernate.boot.archive.scan.spi.ScanOptions;
|
||||
import org.hibernate.boot.archive.scan.spi.Scanner;
|
||||
import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory;
|
||||
import org.hibernate.boot.model.IdGenerationTypeInterpreter;
|
||||
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter;
|
||||
import org.hibernate.boot.model.TypeContributor;
|
||||
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
|
||||
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
|
||||
|
@ -398,7 +397,7 @@ public interface MetadataBuilder {
|
|||
*/
|
||||
MetadataBuilder applyAttributeConverter(AttributeConverter attributeConverter, boolean autoApply);
|
||||
|
||||
MetadataBuilder applyIdGenerationTypeInterpreter(IdGenerationTypeInterpreter interpreter);
|
||||
MetadataBuilder applyIdGenerationTypeInterpreter(IdGeneratorStrategyInterpreter interpreter);
|
||||
|
||||
|
||||
// /**
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2015, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.boot.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.GenerationType;
|
||||
|
||||
import org.hibernate.boot.model.IdGenerationTypeInterpreter;
|
||||
import org.hibernate.id.MultipleHiLoPerTableGenerator;
|
||||
import org.hibernate.id.UUIDGenerator;
|
||||
|
||||
/**
|
||||
* The root (composition) IdGenerationTypeInterpreter.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class IdGenerationTypeInterpreterImpl implements IdGenerationTypeInterpreter {
|
||||
private IdGenerationTypeInterpreter fallbackInterpreter = FallbackInterpreter.INSTANCE;
|
||||
private ArrayList<IdGenerationTypeInterpreter> delegates;
|
||||
|
||||
@Override
|
||||
public String determineGeneratorName(GenerationType generationType, Context context) {
|
||||
if ( delegates != null ) {
|
||||
for ( IdGenerationTypeInterpreter delegate : delegates ) {
|
||||
final String result = delegate.determineGeneratorName( generationType, context );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fallbackInterpreter.determineGeneratorName( generationType, context );
|
||||
}
|
||||
|
||||
public void enableLegacyFallback() {
|
||||
fallbackInterpreter = LegacyFallbackInterpreter.INSTANCE;
|
||||
}
|
||||
|
||||
public void disableLegacyFallback() {
|
||||
fallbackInterpreter = FallbackInterpreter.INSTANCE;
|
||||
}
|
||||
|
||||
public void addInterpreterDelegate(IdGenerationTypeInterpreter delegate) {
|
||||
if ( delegates == null ) {
|
||||
delegates = new ArrayList<IdGenerationTypeInterpreter>();
|
||||
}
|
||||
delegates.add( delegate );
|
||||
}
|
||||
|
||||
private static class LegacyFallbackInterpreter implements IdGenerationTypeInterpreter {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final LegacyFallbackInterpreter INSTANCE = new LegacyFallbackInterpreter();
|
||||
|
||||
@Override
|
||||
public String determineGeneratorName(GenerationType generationType, Context context) {
|
||||
switch ( generationType ) {
|
||||
case IDENTITY: {
|
||||
return "identity";
|
||||
}
|
||||
case SEQUENCE: {
|
||||
return "seqhilo";
|
||||
}
|
||||
case TABLE: {
|
||||
return MultipleHiLoPerTableGenerator.class.getName();
|
||||
}
|
||||
default: {
|
||||
// AUTO
|
||||
final Class javaType = context.getIdType();
|
||||
if ( UUID.class.isAssignableFrom( javaType ) ) {
|
||||
return UUIDGenerator.class.getName();
|
||||
}
|
||||
else {
|
||||
return "native";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class FallbackInterpreter implements IdGenerationTypeInterpreter {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final FallbackInterpreter INSTANCE = new FallbackInterpreter();
|
||||
|
||||
@Override
|
||||
public String determineGeneratorName(GenerationType generationType, Context context) {
|
||||
switch ( generationType ) {
|
||||
case IDENTITY: {
|
||||
return "identity";
|
||||
}
|
||||
case SEQUENCE: {
|
||||
return org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName();
|
||||
}
|
||||
case TABLE: {
|
||||
return org.hibernate.id.enhanced.TableGenerator.class.getName();
|
||||
}
|
||||
default: {
|
||||
// AUTO
|
||||
final Class javaType = context.getIdType();
|
||||
if ( UUID.class.isAssignableFrom( javaType ) ) {
|
||||
return UUIDGenerator.class.getName();
|
||||
}
|
||||
else {
|
||||
return org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2015, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.boot.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.TableGenerator;
|
||||
|
||||
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.BinderHelper;
|
||||
import org.hibernate.id.MultipleHiLoPerTableGenerator;
|
||||
import org.hibernate.id.PersistentIdentifierGenerator;
|
||||
import org.hibernate.id.SequenceHiLoGenerator;
|
||||
import org.hibernate.id.UUIDGenerator;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
|
||||
/**
|
||||
* The root (composition) IdGenerationTypeInterpreter.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class IdGeneratorInterpreterImpl implements IdGeneratorStrategyInterpreter {
|
||||
private static final CoreMessageLogger log = CoreLogging.messageLogger( IdGeneratorInterpreterImpl.class );
|
||||
|
||||
private IdGeneratorStrategyInterpreter fallbackInterpreter = FallbackInterpreter.INSTANCE;
|
||||
private ArrayList<IdGeneratorStrategyInterpreter> delegates;
|
||||
|
||||
@Override
|
||||
public String determineGeneratorName(GenerationType generationType, GeneratorNameDeterminationContext context) {
|
||||
if ( delegates != null ) {
|
||||
for ( IdGeneratorStrategyInterpreter delegate : delegates ) {
|
||||
final String result = delegate.determineGeneratorName( generationType, context );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fallbackInterpreter.determineGeneratorName( generationType, context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interpretTableGenerator(
|
||||
TableGenerator tableGeneratorAnnotation,
|
||||
IdentifierGeneratorDefinition.Builder definitionBuilder) {
|
||||
fallbackInterpreter.interpretTableGenerator( tableGeneratorAnnotation, definitionBuilder );
|
||||
|
||||
if ( delegates != null ) {
|
||||
for ( IdGeneratorStrategyInterpreter delegate : delegates ) {
|
||||
delegate.interpretTableGenerator( tableGeneratorAnnotation, definitionBuilder );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interpretSequenceGenerator(
|
||||
SequenceGenerator sequenceGeneratorAnnotation,
|
||||
IdentifierGeneratorDefinition.Builder definitionBuilder) {
|
||||
fallbackInterpreter.interpretSequenceGenerator( sequenceGeneratorAnnotation, definitionBuilder );
|
||||
|
||||
if ( delegates != null ) {
|
||||
for ( IdGeneratorStrategyInterpreter delegate : delegates ) {
|
||||
delegate.interpretSequenceGenerator( sequenceGeneratorAnnotation, definitionBuilder );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void enableLegacyFallback() {
|
||||
fallbackInterpreter = LegacyFallbackInterpreter.INSTANCE;
|
||||
}
|
||||
|
||||
public void disableLegacyFallback() {
|
||||
fallbackInterpreter = FallbackInterpreter.INSTANCE;
|
||||
}
|
||||
|
||||
public void addInterpreterDelegate(IdGeneratorStrategyInterpreter delegate) {
|
||||
if ( delegates == null ) {
|
||||
delegates = new ArrayList<IdGeneratorStrategyInterpreter>();
|
||||
}
|
||||
delegates.add( delegate );
|
||||
}
|
||||
|
||||
private static class LegacyFallbackInterpreter implements IdGeneratorStrategyInterpreter {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final LegacyFallbackInterpreter INSTANCE = new LegacyFallbackInterpreter();
|
||||
|
||||
@Override
|
||||
public String determineGeneratorName(GenerationType generationType, GeneratorNameDeterminationContext context) {
|
||||
switch ( generationType ) {
|
||||
case IDENTITY: {
|
||||
return "identity";
|
||||
}
|
||||
case SEQUENCE: {
|
||||
return "seqhilo";
|
||||
}
|
||||
case TABLE: {
|
||||
return MultipleHiLoPerTableGenerator.class.getName();
|
||||
}
|
||||
default: {
|
||||
// AUTO
|
||||
final Class javaType = context.getIdType();
|
||||
if ( UUID.class.isAssignableFrom( javaType ) ) {
|
||||
return UUIDGenerator.class.getName();
|
||||
}
|
||||
else {
|
||||
return "native";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interpretTableGenerator(
|
||||
TableGenerator tableGeneratorAnnotation,
|
||||
IdentifierGeneratorDefinition.Builder definitionBuilder) {
|
||||
definitionBuilder.setName( tableGeneratorAnnotation.name() );
|
||||
definitionBuilder.setStrategy( MultipleHiLoPerTableGenerator.class.getName() );
|
||||
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.table() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
MultipleHiLoPerTableGenerator.ID_TABLE,
|
||||
tableGeneratorAnnotation.table()
|
||||
);
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.catalog() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
PersistentIdentifierGenerator.CATALOG,
|
||||
tableGeneratorAnnotation.catalog()
|
||||
);
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.schema() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
PersistentIdentifierGenerator.SCHEMA,
|
||||
tableGeneratorAnnotation.schema()
|
||||
);
|
||||
}
|
||||
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.pkColumnName() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
MultipleHiLoPerTableGenerator.PK_COLUMN_NAME,
|
||||
tableGeneratorAnnotation.pkColumnName()
|
||||
);
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.valueColumnName() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
MultipleHiLoPerTableGenerator.VALUE_COLUMN_NAME,
|
||||
tableGeneratorAnnotation.valueColumnName()
|
||||
);
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.pkColumnValue() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
MultipleHiLoPerTableGenerator.PK_VALUE_NAME,
|
||||
tableGeneratorAnnotation.pkColumnValue()
|
||||
);
|
||||
}
|
||||
definitionBuilder.addParam(
|
||||
MultipleHiLoPerTableGenerator.MAX_LO,
|
||||
String.valueOf( tableGeneratorAnnotation.allocationSize() - 1 )
|
||||
);
|
||||
|
||||
// TODO : implement unique-constraint support
|
||||
if ( tableGeneratorAnnotation.uniqueConstraints() != null
|
||||
&& tableGeneratorAnnotation.uniqueConstraints().length > 0 ) {
|
||||
log.ignoringTableGeneratorConstraints( tableGeneratorAnnotation.name() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void interpretSequenceGenerator(
|
||||
SequenceGenerator sequenceGeneratorAnnotation,
|
||||
IdentifierGeneratorDefinition.Builder definitionBuilder) {
|
||||
definitionBuilder.setName( sequenceGeneratorAnnotation.name() );
|
||||
|
||||
definitionBuilder.setStrategy( "seqhilo" );
|
||||
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( sequenceGeneratorAnnotation.sequenceName() ) ) {
|
||||
definitionBuilder.addParam( org.hibernate.id.SequenceGenerator.SEQUENCE, sequenceGeneratorAnnotation.sequenceName() );
|
||||
}
|
||||
//FIXME: work on initialValue() through SequenceGenerator.PARAMETERS
|
||||
// steve : or just use o.h.id.enhanced.SequenceStyleGenerator
|
||||
if ( sequenceGeneratorAnnotation.initialValue() != 1 ) {
|
||||
log.unsupportedInitialValue( AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS );
|
||||
}
|
||||
definitionBuilder.addParam( SequenceHiLoGenerator.MAX_LO, String.valueOf( sequenceGeneratorAnnotation.allocationSize() - 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
private static class FallbackInterpreter implements IdGeneratorStrategyInterpreter {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final FallbackInterpreter INSTANCE = new FallbackInterpreter();
|
||||
|
||||
@Override
|
||||
public String determineGeneratorName(GenerationType generationType, GeneratorNameDeterminationContext context) {
|
||||
switch ( generationType ) {
|
||||
case IDENTITY: {
|
||||
return "identity";
|
||||
}
|
||||
case SEQUENCE: {
|
||||
return org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName();
|
||||
}
|
||||
case TABLE: {
|
||||
return org.hibernate.id.enhanced.TableGenerator.class.getName();
|
||||
}
|
||||
default: {
|
||||
// AUTO
|
||||
final Class javaType = context.getIdType();
|
||||
if ( UUID.class.isAssignableFrom( javaType ) ) {
|
||||
return UUIDGenerator.class.getName();
|
||||
}
|
||||
else {
|
||||
return org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interpretTableGenerator(
|
||||
TableGenerator tableGeneratorAnnotation,
|
||||
IdentifierGeneratorDefinition.Builder definitionBuilder) {
|
||||
definitionBuilder.setName( tableGeneratorAnnotation.name() );
|
||||
definitionBuilder.setStrategy( org.hibernate.id.enhanced.TableGenerator.class.getName() );
|
||||
definitionBuilder.addParam( org.hibernate.id.enhanced.TableGenerator.CONFIG_PREFER_SEGMENT_PER_ENTITY, "true" );
|
||||
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.catalog() ) ) {
|
||||
definitionBuilder.addParam( PersistentIdentifierGenerator.CATALOG, tableGeneratorAnnotation.catalog() );
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.schema() ) ) {
|
||||
definitionBuilder.addParam( PersistentIdentifierGenerator.SCHEMA, tableGeneratorAnnotation.schema() );
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.table() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
org.hibernate.id.enhanced.TableGenerator.TABLE_PARAM,
|
||||
tableGeneratorAnnotation.table()
|
||||
);
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.pkColumnName() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
org.hibernate.id.enhanced.TableGenerator.SEGMENT_COLUMN_PARAM,
|
||||
tableGeneratorAnnotation.pkColumnName()
|
||||
);
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.pkColumnValue() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
org.hibernate.id.enhanced.TableGenerator.SEGMENT_VALUE_PARAM,
|
||||
tableGeneratorAnnotation.pkColumnValue()
|
||||
);
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tableGeneratorAnnotation.valueColumnName() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
org.hibernate.id.enhanced.TableGenerator.VALUE_COLUMN_PARAM,
|
||||
tableGeneratorAnnotation.valueColumnName()
|
||||
);
|
||||
}
|
||||
definitionBuilder.addParam(
|
||||
org.hibernate.id.enhanced.TableGenerator.INCREMENT_PARAM,
|
||||
String.valueOf( tableGeneratorAnnotation.allocationSize() )
|
||||
);
|
||||
// See comment on HHH-4884 wrt initialValue. Basically initialValue is really the stated value + 1
|
||||
definitionBuilder.addParam(
|
||||
org.hibernate.id.enhanced.TableGenerator.INITIAL_PARAM,
|
||||
String.valueOf( tableGeneratorAnnotation.initialValue() + 1 )
|
||||
);
|
||||
|
||||
// TODO : implement unique-constraint support
|
||||
if ( tableGeneratorAnnotation.uniqueConstraints() != null
|
||||
&& tableGeneratorAnnotation.uniqueConstraints().length > 0 ) {
|
||||
log.ignoringTableGeneratorConstraints( tableGeneratorAnnotation.name() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interpretSequenceGenerator(
|
||||
SequenceGenerator sequenceGeneratorAnnotation,
|
||||
IdentifierGeneratorDefinition.Builder definitionBuilder) {
|
||||
definitionBuilder.setName( sequenceGeneratorAnnotation.name() );
|
||||
definitionBuilder.setStrategy( SequenceStyleGenerator.class.getName() );
|
||||
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( sequenceGeneratorAnnotation.catalog() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
PersistentIdentifierGenerator.CATALOG,
|
||||
sequenceGeneratorAnnotation.catalog()
|
||||
);
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( sequenceGeneratorAnnotation.schema() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
PersistentIdentifierGenerator.SCHEMA,
|
||||
sequenceGeneratorAnnotation.schema()
|
||||
);
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( sequenceGeneratorAnnotation.sequenceName() ) ) {
|
||||
definitionBuilder.addParam(
|
||||
SequenceStyleGenerator.SEQUENCE_PARAM,
|
||||
sequenceGeneratorAnnotation.sequenceName()
|
||||
);
|
||||
}
|
||||
|
||||
definitionBuilder.addParam(
|
||||
SequenceStyleGenerator.INCREMENT_PARAM,
|
||||
String.valueOf( sequenceGeneratorAnnotation.allocationSize() )
|
||||
);
|
||||
definitionBuilder.addParam(
|
||||
SequenceStyleGenerator.INITIAL_PARAM,
|
||||
String.valueOf( sequenceGeneratorAnnotation.initialValue() )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,7 +49,7 @@ import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory;
|
|||
import org.hibernate.boot.cfgxml.spi.CfgXmlAccessService;
|
||||
import org.hibernate.boot.cfgxml.spi.LoadedConfig;
|
||||
import org.hibernate.boot.cfgxml.spi.MappingReference;
|
||||
import org.hibernate.boot.model.IdGenerationTypeInterpreter;
|
||||
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.boot.model.TypeContributor;
|
||||
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
|
||||
|
@ -380,7 +380,6 @@ public class MetadataBuilderImpl implements MetadataBuilder, TypeContributions {
|
|||
|
||||
@Override
|
||||
public MetadataBuilder enableNewIdentifierGeneratorSupport(boolean enabled) {
|
||||
this.options.useNewIdentifierGenerators = enabled;
|
||||
if ( enabled ) {
|
||||
this.options.idGenerationTypeInterpreter.disableLegacyFallback();
|
||||
}
|
||||
|
@ -391,7 +390,7 @@ public class MetadataBuilderImpl implements MetadataBuilder, TypeContributions {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MetadataBuilder applyIdGenerationTypeInterpreter(IdGenerationTypeInterpreter interpreter) {
|
||||
public MetadataBuilder applyIdGenerationTypeInterpreter(IdGeneratorStrategyInterpreter interpreter) {
|
||||
this.options.idGenerationTypeInterpreter.addInterpreterDelegate( interpreter );
|
||||
return this;
|
||||
}
|
||||
|
@ -556,8 +555,7 @@ public class MetadataBuilderImpl implements MetadataBuilder, TypeContributions {
|
|||
private ArrayList<AuxiliaryDatabaseObject> auxiliaryDatabaseObjectList;
|
||||
private HashMap<Class,AttributeConverterDefinition> attributeConverterDefinitionsByClass;
|
||||
|
||||
private boolean useNewIdentifierGenerators;
|
||||
private IdGenerationTypeInterpreterImpl idGenerationTypeInterpreter = new IdGenerationTypeInterpreterImpl();
|
||||
private IdGeneratorInterpreterImpl idGenerationTypeInterpreter = new IdGeneratorInterpreterImpl();
|
||||
|
||||
private static ReflectionManager generateDefaultReflectionManager() {
|
||||
final JavaReflectionManager reflectionManager = new JavaReflectionManager();
|
||||
|
@ -679,7 +677,7 @@ public class MetadataBuilderImpl implements MetadataBuilder, TypeContributions {
|
|||
|
||||
sourceProcessOrdering = resolveInitialSourceProcessOrdering( configService );
|
||||
|
||||
useNewIdentifierGenerators = configService.getSetting(
|
||||
final boolean useNewIdentifierGenerators = configService.getSetting(
|
||||
AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS,
|
||||
StandardConverters.BOOLEAN,
|
||||
false
|
||||
|
@ -790,12 +788,7 @@ public class MetadataBuilderImpl implements MetadataBuilder, TypeContributions {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseNewIdentifierGenerators() {
|
||||
return useNewIdentifierGenerators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdGenerationTypeInterpreter getIdGenerationTypeInterpreter() {
|
||||
public IdGeneratorStrategyInterpreter getIdGenerationTypeInterpreter() {
|
||||
return idGenerationTypeInterpreter;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2015, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.boot.model;
|
||||
|
||||
import javax.persistence.GenerationType;
|
||||
|
||||
/**
|
||||
* Delegate for interpreting the name of the IdentifierGenerator to use based on
|
||||
* GenerationType.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface IdGenerationTypeInterpreter {
|
||||
public static interface Context {
|
||||
public Class getIdType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the name of the generator which should be used, returning {@code null} to
|
||||
* indicate that this interpreter did not have a match and that any additional resolutions
|
||||
* should be performed.
|
||||
*
|
||||
* @param generationType The {@link javax.persistence.GeneratedValue#strategy} value
|
||||
* @param context The context for resolution (method parameter object)
|
||||
*/
|
||||
String determineGeneratorName(GenerationType generationType, Context context);
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2015, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.boot.model;
|
||||
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.TableGenerator;
|
||||
|
||||
/**
|
||||
* Strategy for interpreting identifier generator related information.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface IdGeneratorStrategyInterpreter {
|
||||
public static interface GeneratorNameDeterminationContext {
|
||||
public Class getIdType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the name of the generator which should be used based on the
|
||||
* GenerationType, returning {@code null} to indicate that this interpreter
|
||||
* did not have a match and that any additional resolutions should be performed.
|
||||
*
|
||||
* @param generationType The {@link javax.persistence.GeneratedValue#strategy} value
|
||||
* @param context The context for resolution (method parameter object)
|
||||
*/
|
||||
String determineGeneratorName(GenerationType generationType, GeneratorNameDeterminationContext context);
|
||||
|
||||
/**
|
||||
* Extract the IdentifierGeneratorDefinition related to the given TableGenerator annotation
|
||||
*
|
||||
* @param tableGeneratorAnnotation The annotation
|
||||
* @param definitionBuilder The IdentifierGeneratorDefinition builder to which to apply
|
||||
* any interpreted/extracted configuration
|
||||
*/
|
||||
void interpretTableGenerator(TableGenerator tableGeneratorAnnotation, IdentifierGeneratorDefinition.Builder definitionBuilder);
|
||||
|
||||
/**
|
||||
* Extract the IdentifierGeneratorDefinition related to the given SequenceGenerator annotation
|
||||
*
|
||||
* @param sequenceGeneratorAnnotation The annotation
|
||||
* @param definitionBuilder The IdentifierGeneratorDefinition builder to which to apply
|
||||
* any interpreted/extracted configuration
|
||||
*/
|
||||
void interpretSequenceGenerator(SequenceGenerator sequenceGeneratorAnnotation, IdentifierGeneratorDefinition.Builder definitionBuilder);
|
||||
}
|
|
@ -33,7 +33,7 @@ import org.hibernate.boot.CacheRegionDefinition;
|
|||
import org.hibernate.boot.archive.scan.spi.ScanEnvironment;
|
||||
import org.hibernate.boot.archive.scan.spi.ScanOptions;
|
||||
import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory;
|
||||
import org.hibernate.boot.model.IdGenerationTypeInterpreter;
|
||||
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter;
|
||||
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
|
||||
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
|
||||
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
|
||||
|
@ -155,16 +155,7 @@ public interface MetadataBuildingOptions {
|
|||
*/
|
||||
MultiTenancyStrategy getMultiTenancyStrategy();
|
||||
|
||||
/**
|
||||
* Access to whether we should be using the new identifier generator scheme.
|
||||
* {@code true} indicates to use the new schema, {@code false} indicates to use the
|
||||
* legacy scheme.
|
||||
*
|
||||
* @return Whether to use the new identifier generator scheme
|
||||
*/
|
||||
boolean isUseNewIdentifierGenerators();
|
||||
|
||||
IdGenerationTypeInterpreter getIdGenerationTypeInterpreter();
|
||||
IdGeneratorStrategyInterpreter getIdGenerationTypeInterpreter();
|
||||
|
||||
/**
|
||||
* Access to all explicit cache region mappings.
|
||||
|
|
|
@ -36,7 +36,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.CollectionTable;
|
||||
|
@ -145,7 +144,7 @@ import org.hibernate.annotations.common.reflection.XClass;
|
|||
import org.hibernate.annotations.common.reflection.XMethod;
|
||||
import org.hibernate.annotations.common.reflection.XPackage;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.boot.model.IdGenerationTypeInterpreter;
|
||||
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.boot.model.TypeDefinition;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector.EntityTableXref;
|
||||
|
@ -161,11 +160,7 @@ import org.hibernate.cfg.annotations.SimpleValueBinder;
|
|||
import org.hibernate.cfg.annotations.TableBinder;
|
||||
import org.hibernate.engine.OptimisticLockStyle;
|
||||
import org.hibernate.engine.spi.FilterDefinition;
|
||||
import org.hibernate.id.MultipleHiLoPerTableGenerator;
|
||||
import org.hibernate.id.PersistentIdentifierGenerator;
|
||||
import org.hibernate.id.SequenceHiLoGenerator;
|
||||
import org.hibernate.id.UUIDGenerator;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
|
@ -437,146 +432,61 @@ public final class AnnotationBinder {
|
|||
}
|
||||
|
||||
private static IdentifierGeneratorDefinition buildIdGenerator(java.lang.annotation.Annotation ann, MetadataBuildingContext context) {
|
||||
IdentifierGeneratorDefinition.Builder idGen = new IdentifierGeneratorDefinition.Builder();
|
||||
if ( ann == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
IdentifierGeneratorDefinition.Builder definitionBuilder = new IdentifierGeneratorDefinition.Builder();
|
||||
|
||||
if ( context.getMappingDefaults().getImplicitSchemaName() != null ) {
|
||||
idGen.addParam( PersistentIdentifierGenerator.SCHEMA, context.getMappingDefaults().getImplicitSchemaName() );
|
||||
definitionBuilder.addParam(
|
||||
PersistentIdentifierGenerator.SCHEMA,
|
||||
context.getMappingDefaults().getImplicitSchemaName()
|
||||
);
|
||||
}
|
||||
|
||||
if ( context.getMappingDefaults().getImplicitCatalogName() != null ) {
|
||||
idGen.addParam( PersistentIdentifierGenerator.CATALOG, context.getMappingDefaults().getImplicitCatalogName() );
|
||||
definitionBuilder.addParam(
|
||||
PersistentIdentifierGenerator.CATALOG,
|
||||
context.getMappingDefaults().getImplicitCatalogName()
|
||||
);
|
||||
}
|
||||
|
||||
final boolean useNewGeneratorMappings = context.getBuildingOptions().isUseNewIdentifierGenerators();
|
||||
if ( ann == null ) {
|
||||
idGen = null;
|
||||
}
|
||||
else if ( ann instanceof TableGenerator ) {
|
||||
TableGenerator tabGen = ( TableGenerator ) ann;
|
||||
idGen.setName( tabGen.name() );
|
||||
if ( useNewGeneratorMappings ) {
|
||||
idGen.setStrategy( org.hibernate.id.enhanced.TableGenerator.class.getName() );
|
||||
idGen.addParam( org.hibernate.id.enhanced.TableGenerator.CONFIG_PREFER_SEGMENT_PER_ENTITY, "true" );
|
||||
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.catalog() ) ) {
|
||||
idGen.addParam( PersistentIdentifierGenerator.CATALOG, tabGen.catalog() );
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.schema() ) ) {
|
||||
idGen.addParam( PersistentIdentifierGenerator.SCHEMA, tabGen.schema() );
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.table() ) ) {
|
||||
idGen.addParam( org.hibernate.id.enhanced.TableGenerator.TABLE_PARAM, tabGen.table() );
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.pkColumnName() ) ) {
|
||||
idGen.addParam(
|
||||
org.hibernate.id.enhanced.TableGenerator.SEGMENT_COLUMN_PARAM, tabGen.pkColumnName()
|
||||
);
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.pkColumnValue() ) ) {
|
||||
idGen.addParam(
|
||||
org.hibernate.id.enhanced.TableGenerator.SEGMENT_VALUE_PARAM, tabGen.pkColumnValue()
|
||||
);
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.valueColumnName() ) ) {
|
||||
idGen.addParam(
|
||||
org.hibernate.id.enhanced.TableGenerator.VALUE_COLUMN_PARAM, tabGen.valueColumnName()
|
||||
);
|
||||
}
|
||||
idGen.addParam(
|
||||
org.hibernate.id.enhanced.TableGenerator.INCREMENT_PARAM,
|
||||
String.valueOf( tabGen.allocationSize() )
|
||||
);
|
||||
// See comment on HHH-4884 wrt initialValue. Basically initialValue is really the stated value + 1
|
||||
idGen.addParam(
|
||||
org.hibernate.id.enhanced.TableGenerator.INITIAL_PARAM,
|
||||
String.valueOf( tabGen.initialValue() + 1 )
|
||||
);
|
||||
if (tabGen.uniqueConstraints() != null && tabGen.uniqueConstraints().length > 0) {
|
||||
LOG.warn( tabGen.name() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
idGen.setStrategy( MultipleHiLoPerTableGenerator.class.getName() );
|
||||
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.table() ) ) {
|
||||
idGen.addParam( MultipleHiLoPerTableGenerator.ID_TABLE, tabGen.table() );
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.catalog() ) ) {
|
||||
idGen.addParam( PersistentIdentifierGenerator.CATALOG, tabGen.catalog() );
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.schema() ) ) {
|
||||
idGen.addParam( PersistentIdentifierGenerator.SCHEMA, tabGen.schema() );
|
||||
}
|
||||
//FIXME implement uniqueconstrains
|
||||
if (tabGen.uniqueConstraints() != null && tabGen.uniqueConstraints().length > 0) LOG.ignoringTableGeneratorConstraints(tabGen.name());
|
||||
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.pkColumnName() ) ) {
|
||||
idGen.addParam( MultipleHiLoPerTableGenerator.PK_COLUMN_NAME, tabGen.pkColumnName() );
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.valueColumnName() ) ) {
|
||||
idGen.addParam( MultipleHiLoPerTableGenerator.VALUE_COLUMN_NAME, tabGen.valueColumnName() );
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( tabGen.pkColumnValue() ) ) {
|
||||
idGen.addParam( MultipleHiLoPerTableGenerator.PK_VALUE_NAME, tabGen.pkColumnValue() );
|
||||
}
|
||||
idGen.addParam( MultipleHiLoPerTableGenerator.MAX_LO, String.valueOf( tabGen.allocationSize() - 1 ) );
|
||||
}
|
||||
if ( ann instanceof TableGenerator ) {
|
||||
context.getBuildingOptions().getIdGenerationTypeInterpreter().interpretTableGenerator(
|
||||
(TableGenerator) ann,
|
||||
definitionBuilder
|
||||
);
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add table generator with name: {0}", idGen.getName() );
|
||||
LOG.tracev( "Add table generator with name: {0}", definitionBuilder.getName() );
|
||||
}
|
||||
}
|
||||
else if ( ann instanceof SequenceGenerator ) {
|
||||
SequenceGenerator seqGen = ( SequenceGenerator ) ann;
|
||||
idGen.setName( seqGen.name() );
|
||||
if ( useNewGeneratorMappings ) {
|
||||
idGen.setStrategy( SequenceStyleGenerator.class.getName() );
|
||||
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( seqGen.catalog() ) ) {
|
||||
idGen.addParam( PersistentIdentifierGenerator.CATALOG, seqGen.catalog() );
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( seqGen.schema() ) ) {
|
||||
idGen.addParam( PersistentIdentifierGenerator.SCHEMA, seqGen.schema() );
|
||||
}
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( seqGen.sequenceName() ) ) {
|
||||
idGen.addParam( SequenceStyleGenerator.SEQUENCE_PARAM, seqGen.sequenceName() );
|
||||
}
|
||||
idGen.addParam( SequenceStyleGenerator.INCREMENT_PARAM, String.valueOf( seqGen.allocationSize() ) );
|
||||
idGen.addParam( SequenceStyleGenerator.INITIAL_PARAM, String.valueOf( seqGen.initialValue() ) );
|
||||
}
|
||||
else {
|
||||
idGen.setStrategy( "seqhilo" );
|
||||
|
||||
if ( !BinderHelper.isEmptyAnnotationValue( seqGen.sequenceName() ) ) {
|
||||
idGen.addParam( org.hibernate.id.SequenceGenerator.SEQUENCE, seqGen.sequenceName() );
|
||||
}
|
||||
//FIXME: work on initialValue() through SequenceGenerator.PARAMETERS
|
||||
// steve : or just use o.h.id.enhanced.SequenceStyleGenerator
|
||||
if ( seqGen.initialValue() != 1 ) {
|
||||
LOG.unsupportedInitialValue( AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS );
|
||||
}
|
||||
idGen.addParam( SequenceHiLoGenerator.MAX_LO, String.valueOf( seqGen.allocationSize() - 1 ) );
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add sequence generator with name: {0}", idGen.getName() );
|
||||
}
|
||||
context.getBuildingOptions().getIdGenerationTypeInterpreter().interpretSequenceGenerator(
|
||||
(SequenceGenerator) ann,
|
||||
definitionBuilder
|
||||
);
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add sequence generator with name: {0}", definitionBuilder.getName() );
|
||||
}
|
||||
}
|
||||
else if ( ann instanceof GenericGenerator ) {
|
||||
GenericGenerator genGen = ( GenericGenerator ) ann;
|
||||
idGen.setName( genGen.name() );
|
||||
idGen.setStrategy( genGen.strategy() );
|
||||
definitionBuilder.setName( genGen.name() );
|
||||
definitionBuilder.setStrategy( genGen.strategy() );
|
||||
Parameter[] params = genGen.parameters();
|
||||
for ( Parameter parameter : params ) {
|
||||
idGen.addParam( parameter.name(), parameter.value() );
|
||||
definitionBuilder.addParam( parameter.name(), parameter.value() );
|
||||
}
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add generic generator with name: {0}", idGen.getName() );
|
||||
LOG.tracev( "Add generic generator with name: {0}", definitionBuilder.getName() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure( "Unknown Generator annotation: " + ann );
|
||||
}
|
||||
|
||||
return idGen.build();
|
||||
return definitionBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3236,7 +3146,7 @@ public final class AnnotationBinder {
|
|||
final XClass javaTypeXClass) {
|
||||
return buildingContext.getBuildingOptions().getIdGenerationTypeInterpreter().determineGeneratorName(
|
||||
generatorEnum,
|
||||
new IdGenerationTypeInterpreter.Context() {
|
||||
new IdGeneratorStrategyInterpreter.GeneratorNameDeterminationContext() {
|
||||
Class javaType = null;
|
||||
@Override
|
||||
public Class getIdType() {
|
||||
|
|
Loading…
Reference in New Issue