Skip to content

Commit

Permalink
Fixes for Yoann's search + 6.0 tracking
Browse files Browse the repository at this point in the history
- Support for generated values
- See `@ProposedGenerated` for proposed change to `@Generated`; without that change, `@Generated` will not work with update-generation; nor does it work on 5.x
  • Loading branch information
sebersole committed Aug 2, 2021
1 parent b8afa46 commit 230c787
Show file tree
Hide file tree
Showing 56 changed files with 2,546 additions and 541 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ protected String originalMessage() {
@Override
public String getMessage() {
return originalMessage()
+ ( wasSetter ? " setter of " : " getter of " )
+ StringHelper.qualify( persistentClass.getName(), propertyName );
+ " : `" + StringHelper.qualify( persistentClass.getName(), propertyName )
+ ( wasSetter ? "` (setter)" : "` (getter)" );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -348,13 +348,15 @@ private ValueGeneration determineValueGenerationStrategy(XProperty property) {
return NoValueGeneration.INSTANCE;
}

final GenerationTiming when = valueGeneration.getGenerationTiming();

if ( valueGeneration.getValueGenerator() == null ) {
// if we have an in-db generator, mark it as not insertable nor updatable
insertable = false;
if ( when == GenerationTiming.ALWAYS ) {
updatable = false;
}
updatable = false;
// final GenerationTiming when = valueGeneration.getGenerationTiming();
// if ( when == GenerationTiming.ALWAYS ) {
// // it should also be not-updatable
// updatable = false;
// }
}

return valueGeneration;
Expand Down Expand Up @@ -394,21 +396,18 @@ private ValueGeneration getValueGenerationFromAnnotations(XProperty property) {
private <A extends Annotation> AnnotationValueGeneration<A> getValueGenerationFromAnnotation(
XProperty property,
A annotation) {
ValueGenerationType generatorAnnotation = annotation.annotationType()
.getAnnotation( ValueGenerationType.class );
final ValueGenerationType generatorAnnotation = annotation.annotationType().getAnnotation( ValueGenerationType.class );

if ( generatorAnnotation == null ) {
return null;
}

Class<? extends AnnotationValueGeneration<?>> generationType = generatorAnnotation.generatedBy();
AnnotationValueGeneration<A> valueGeneration = instantiateAndInitializeValueGeneration(
annotation, generationType, property
);
final Class<? extends AnnotationValueGeneration<?>> generationType = generatorAnnotation.generatedBy();
final AnnotationValueGeneration<A> valueGeneration = instantiateAndInitializeValueGeneration( annotation, generationType, property );

if ( annotation.annotationType() == Generated.class &&
property.isAnnotationPresent( javax.persistence.Version.class ) &&
valueGeneration.getGenerationTiming() == GenerationTiming.INSERT ) {
if ( annotation.annotationType() == Generated.class
&& property.isAnnotationPresent( javax.persistence.Version.class )
&& valueGeneration.getGenerationTiming() == GenerationTiming.INSERT ) {

throw new AnnotationException(
"@Generated(INSERT) on a @Version property not allowed, use ALWAYS (or NEVER): "
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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.internal.util;

/**
* Support for mutable boolean references, generally used from within
* anon inner classes, lambdas, etc
*
* @author Steve Ebersole
*/
public class MutableBoolean {
private boolean value;

public MutableBoolean() {
}

public MutableBoolean(boolean value) {
this.value = value;
}

public boolean getValue() {
return value;
}

public void setValue(boolean value) {
this.value = value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.descriptor.java.MutabilityPlanExposer;

Expand All @@ -28,8 +29,18 @@ default String getPartName() {

ManagedMappingType getDeclaringType();

/**
* The getter/setter access to this attribute
*/
PropertyAccess getPropertyAccess();

/**
* The value generation strategy to use for this attribute.
*
* @apiNote Only relevant for non-id attributes
*/
ValueGeneration getValueGeneration();

@Override
default EntityMappingType findContainingEntityMapping() {
return getDeclaringType().findContainingEntityMapping();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,15 @@
package org.hibernate.metamodel.mapping;

/**
* Provides access to details about an attribute specific to a particular
* entity in the hierarchy. Accounts for attribute/association overrides, etc
*
* @author Steve Ebersole
*/
@FunctionalInterface
public interface AttributeMetadataAccess {
/**
* Resolve the details about the attribute
*/
AttributeMetadata resolveAttributeMetadata(EntityMappingType entityMappingType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ private EmbeddableMappingType(
attributeMapping = BasicAttributeMapping.withSelectableMapping(
original,
original.getPropertyAccess(),
original.getValueGeneration(),
selectableMapping
);
currentIndex++;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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.mapping;

import org.hibernate.Incubating;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.internal.NoGeneratedValueResolver;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.ValueGeneration;

/**
* Generalized contract covering an attribute's generation handling
*
* @author Steve Ebersole
*/
@Incubating
public interface GeneratedValueResolver {
static GeneratedValueResolver from(
ValueGeneration valueGeneration,
GenerationTiming requestedTiming,
int dbSelectionPosition) {
assert requestedTiming != GenerationTiming.NEVER;

if ( valueGeneration == null || valueGeneration.getGenerationTiming().includes( GenerationTiming.NEVER ) ) {
return NoGeneratedValueResolver.INSTANCE;
}

if ( requestedTiming == GenerationTiming.ALWAYS && valueGeneration.getGenerationTiming() == GenerationTiming.INSERT ) {
return NoGeneratedValueResolver.INSTANCE;
}

// todo (6.x) : incorporate `org.hibernate.tuple.InDatabaseValueGenerationStrategy`
// and `org.hibernate.tuple.InMemoryValueGenerationStrategy` from `EntityMetamodel`.
// this requires unification of the read and write (insert/update) aspects of
// value generation which we'll circle back to as we convert write operations to
// use the "runtime mapping" (`org.hibernate.metamodel.mapping`) model

if ( valueGeneration.getValueGenerator() == null ) {
// in-db generation (column-default, function, etc)
return new InDatabaseGeneratedValueResolver( requestedTiming, dbSelectionPosition );
}

return new InMemoryGeneratedValueResolver( valueGeneration.getValueGenerator(), requestedTiming );
}

GenerationTiming getGenerationTiming();
Object resolveGeneratedValue(Object[] row, Object entity, SharedSessionContractImplementor session);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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.mapping;

import org.hibernate.Internal;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.tuple.GenerationTiming;

/**
* GeneratedValueResolver impl for in-db generation. It extracts the generated value
* from a array of the ResultSet values
*
* @author Steve Ebersole
*/
@Internal
public class InDatabaseGeneratedValueResolver implements GeneratedValueResolver {
private final GenerationTiming timing;
private final int resultPosition;

public InDatabaseGeneratedValueResolver(GenerationTiming timing, int resultPosition) {
this.timing = timing;
this.resultPosition = resultPosition;
}

@Override
public GenerationTiming getGenerationTiming() {
return timing;
}

@Override
public Object resolveGeneratedValue(Object[] row, Object entity, SharedSessionContractImplementor session) {
return row[resultPosition];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* 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.mapping;

import org.hibernate.Internal;
import org.hibernate.Session;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.ValueGenerator;

/**
* GeneratedValueResolver impl for in-memory generation
*
* @author Steve Ebersole
*/
@Internal
public class InMemoryGeneratedValueResolver implements GeneratedValueResolver {
private final GenerationTiming generationTiming;
private final ValueGenerator valueGenerator;

public InMemoryGeneratedValueResolver(ValueGenerator valueGenerator, GenerationTiming generationTiming) {
this.valueGenerator = valueGenerator;
this.generationTiming = generationTiming;
}

@Override
public GenerationTiming getGenerationTiming() {
return generationTiming;
}

@Override
public Object resolveGeneratedValue(Object[] row, Object entity, SharedSessionContractImplementor session) {
return valueGenerator.generateValue( (Session) session, entity );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.tuple.ValueGeneration;

/**
* @author Steve Ebersole
Expand All @@ -22,16 +23,21 @@ public abstract class AbstractSingularAttributeMapping
implements SingularAttributeMapping {

private final PropertyAccess propertyAccess;
private final ValueGeneration valueGeneration;

public AbstractSingularAttributeMapping(
String name,
int stateArrayPosition,
StateArrayContributorMetadataAccess attributeMetadataAccess,
FetchOptions mappedFetchOptions,
ManagedMappingType declaringType,
PropertyAccess propertyAccess) {
PropertyAccess propertyAccess,
ValueGeneration valueGeneration) {
super( name, attributeMetadataAccess, mappedFetchOptions, stateArrayPosition, declaringType );
this.propertyAccess = propertyAccess;
this.valueGeneration = valueGeneration != null
? valueGeneration
: NoValueGeneration.INSTANCE;
}

public AbstractSingularAttributeMapping(
Expand All @@ -41,13 +47,22 @@ public AbstractSingularAttributeMapping(
FetchTiming fetchTiming,
FetchStyle fetchStyle,
ManagedMappingType declaringType,
PropertyAccess propertyAccess) {
PropertyAccess propertyAccess,
ValueGeneration valueGeneration) {
super( name, attributeMetadataAccess, fetchTiming, fetchStyle, stateArrayPosition, declaringType );
this.propertyAccess = propertyAccess;
this.valueGeneration = valueGeneration != null
? valueGeneration
: NoValueGeneration.INSTANCE;
}

@Override
public PropertyAccess getPropertyAccess() {
return propertyAccess;
}

@Override
public ValueGeneration getValueGeneration() {
return valueGeneration;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.ConvertibleModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
Expand All @@ -39,6 +39,7 @@
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;

/**
Expand Down Expand Up @@ -77,8 +78,9 @@ public BasicAttributeMapping(
BasicValueConverter valueConverter,
JdbcMapping jdbcMapping,
ManagedMappingType declaringType,
PropertyAccess propertyAccess) {
super( attributeName, stateArrayPosition, attributeMetadataAccess, mappedFetchTiming, mappedFetchStyle, declaringType, propertyAccess );
PropertyAccess propertyAccess,
ValueGeneration valueGeneration) {
super( attributeName, stateArrayPosition, attributeMetadataAccess, mappedFetchTiming, mappedFetchStyle, declaringType, propertyAccess, valueGeneration );
this.navigableRole = navigableRole;
this.tableExpression = tableExpression;
this.mappedColumnExpression = mappedColumnExpression;
Expand Down Expand Up @@ -106,6 +108,7 @@ public BasicAttributeMapping(
public static BasicAttributeMapping withSelectableMapping(
BasicValuedModelPart original,
PropertyAccess propertyAccess,
ValueGeneration valueGeneration,
SelectableMapping selectableMapping) {
String attributeName = null;
int stateArrayPosition = 0;
Expand Down Expand Up @@ -143,7 +146,8 @@ else if ( original instanceof SingularAttributeMapping ) {
valueConverter,
selectableMapping.getJdbcMapping(),
declaringType,
propertyAccess
propertyAccess,
valueGeneration
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ public DiscriminatedAssociationAttributeMapping(
fetchTiming,
FetchStyle.SELECT,
declaringType,
propertyAccess
propertyAccess,
null
);
this.navigableRole = attributeRole;

Expand Down
Loading

0 comments on commit 230c787

Please sign in to comment.