Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,68 @@

import java.util.Map;

import org.hibernate.Internal;
import org.hibernate.boot.registry.StandardServiceInitiator;
import org.hibernate.bytecode.spi.BytecodeProvider;
import org.hibernate.cfg.Environment;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.spi.ServiceRegistryImplementor;

import org.jboss.logging.Logger;

import static org.hibernate.cfg.AvailableSettings.BYTECODE_PROVIDER;

public final class BytecodeProviderInitiator implements StandardServiceInitiator<BytecodeProvider> {

public static final String BYTECODE_PROVIDER_NAME_BYTEBUDDY = "bytebuddy";
public static final String BYTECODE_PROVIDER_NAME_NONE = "none";
public static final String BYTECODE_PROVIDER_NAME_DEFAULT = BYTECODE_PROVIDER_NAME_BYTEBUDDY;

/**
* Singleton access
*/
public static final StandardServiceInitiator<BytecodeProvider> INSTANCE = new BytecodeProviderInitiator();

@Override
public BytecodeProvider initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
// TODO in 6 this will no longer use Environment, which is configured via global environment variables,
// but move to a component which can be reconfigured differently in each registry.
return Environment.getBytecodeProvider();
String provider = ConfigurationHelper.getString( BYTECODE_PROVIDER, configurationValues, BYTECODE_PROVIDER_NAME_DEFAULT );
return buildBytecodeProvider( provider );
}

@Override
public Class<BytecodeProvider> getServiceInitiated() {
return BytecodeProvider.class;
}

@Internal
public static BytecodeProvider buildDefaultBytecodeProvider() {
return buildBytecodeProvider( BYTECODE_PROVIDER_NAME_BYTEBUDDY );
}

@Internal
public static BytecodeProvider buildBytecodeProvider(String providerName) {

CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, BytecodeProviderInitiator.class.getName() );
LOG.bytecodeProvider( providerName );

if ( BYTECODE_PROVIDER_NAME_NONE.equals( providerName ) ) {
return new org.hibernate.bytecode.internal.none.BytecodeProviderImpl();
}
if ( BYTECODE_PROVIDER_NAME_BYTEBUDDY.equals( providerName ) ) {
return new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl();
}

// There is no need to support plugging in a custom BytecodeProvider via FQCN
// as it's possible to plug a custom BytecodeProviderInitiator into the bootstrap.
//
// This also allows integrators to inject a BytecodeProvider instance which has some
// state: particularly useful to inject proxy definitions which have been prepared in
// advance.
// See also https://hibernate.atlassian.net/browse/HHH-13804 and how this was solved in
// Quarkus.

LOG.unknownBytecodeProvider( providerName, BYTECODE_PROVIDER_NAME_DEFAULT );
return new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -1533,7 +1533,7 @@ public interface AvailableSettings {
String CHECK_NULLABILITY = "hibernate.check_nullability";

/**
* Selects a bytecode enhancment library.
* Selects a bytecode enhancement library.
* <p>
* At present only bytebuddy is supported, bytebuddy being the default since version 5.3.
*/
Expand Down
75 changes: 30 additions & 45 deletions hibernate-core/src/main/java/org/hibernate/cfg/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.hibernate.HibernateException;
import org.hibernate.Internal;
import org.hibernate.Version;
import org.hibernate.bytecode.internal.BytecodeProviderInitiator;
import org.hibernate.bytecode.spi.BytecodeProvider;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ConfigHelper;
Expand All @@ -35,8 +36,8 @@
* always determined by the {@code Environment} properties in {@link #getProperties()}.
* </ul>
* <p>
* The only system-level properties are {@value #USE_REFLECTION_OPTIMIZER} and
* {@value #BYTECODE_PROVIDER}.
* The only system-level property is {@value #USE_REFLECTION_OPTIMIZER},
* and it's deprecated.
* <p>
* {@code Environment} properties are populated by calling {@link System#getProperties()}
* and then from a resource named {@code /hibernate.properties}, if it exists. System
Expand Down Expand Up @@ -141,7 +142,6 @@
public final class Environment implements AvailableSettings {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, Environment.class.getName());

private static final BytecodeProvider BYTECODE_PROVIDER_INSTANCE;
private static final boolean ENABLE_REFLECTION_OPTIMIZER;

private static final Properties GLOBAL_PROPERTIES;
Expand Down Expand Up @@ -193,8 +193,6 @@ public final class Environment implements AvailableSettings {
else {
DEPRECATION_LOGGER.deprecatedSettingForRemoval( USE_REFLECTION_OPTIMIZER, "true" );
}

BYTECODE_PROVIDER_INSTANCE = buildBytecodeProvider( GLOBAL_PROPERTIES );
}

/**
Expand All @@ -203,12 +201,11 @@ public final class Environment implements AvailableSettings {
* @return True if reflection optimization should be used; false otherwise.
*
* @see #USE_REFLECTION_OPTIMIZER
* @see #getBytecodeProvider()
* @see BytecodeProvider#getReflectionOptimizer
*
* @deprecated Deprecated to indicate that the method will be moved to
* {@link org.hibernate.boot.spi.SessionFactoryOptions} /
* {@link org.hibernate.boot.SessionFactoryBuilder} - probably in 6.0.
* {@link org.hibernate.boot.SessionFactoryBuilder}.
* See <a href="https://hibernate.atlassian.net/browse/HHH-12194">HHH-12194</a> and
* <a href="https://hibernate.atlassian.net/browse/HHH-12193">HHH-12193</a> for details
*/
Expand All @@ -217,23 +214,11 @@ public static boolean useReflectionOptimizer() {
return ENABLE_REFLECTION_OPTIMIZER;
}

/**
* @deprecated Deprecated to indicate that the method will be moved to
* {@link org.hibernate.boot.spi.SessionFactoryOptions} /
* {@link org.hibernate.boot.SessionFactoryBuilder} - probably in 6.0.
* See <a href="https://hibernate.atlassian.net/browse/HHH-12194">HHH-12194</a> and
* <a href="https://hibernate.atlassian.net/browse/HHH-12193">HHH-12193</a> for details
*/
@Deprecated
public static BytecodeProvider getBytecodeProvider() {
return BYTECODE_PROVIDER_INSTANCE;
}

/**
* Disallow instantiation
*/
private Environment() {
throw new UnsupportedOperationException();
//not to be constructed
}

/**
Expand All @@ -246,36 +231,36 @@ public static Properties getProperties() {
return copy;
}

/**
* @deprecated Replaced by {@code org.hibernate.bytecode.internal.BytecodeProviderInitiator#BYTECODE_PROVIDER_NAME_BYTEBUDDY},
* however note that that's an internal contract: a different BytecodeProvider Initiator might ignore these constants
* or interpret them differently.
*/
@Deprecated(forRemoval = true)
public static final String BYTECODE_PROVIDER_NAME_BYTEBUDDY = "bytebuddy";

/**
* @deprecated Replaced by {@code org.hibernate.bytecode.internal.BytecodeProviderInitiator#BYTECODE_PROVIDER_NAME_NONE},
* however note that that's an internal contract: a different BytecodeProvider Initiator might ignore these constants
* or interpret them differently.
*/
@Deprecated(forRemoval = true)
public static final String BYTECODE_PROVIDER_NAME_NONE = "none";
public static final String BYTECODE_PROVIDER_NAME_DEFAULT = BYTECODE_PROVIDER_NAME_BYTEBUDDY;

/**
* @deprecated Replaced by {@code org.hibernate.bytecode.internal.BytecodeProviderInitiator#BYTECODE_PROVIDER_NAME_DEFAULT}
* however note that that's an internal contract: a different BytecodeProvider Initiator might apply a different default.
*/
@Deprecated(forRemoval = true)
public static final String BYTECODE_PROVIDER_NAME_DEFAULT = BytecodeProviderInitiator.BYTECODE_PROVIDER_NAME_BYTEBUDDY;

/**
* @deprecated this will be removed; retrieval of the BytecodeProvider should be performed via the {@link org.hibernate.service.ServiceRegistry}.
*/
@Deprecated(forRemoval = true)
public static BytecodeProvider buildBytecodeProvider(Properties properties) {
String provider = ConfigurationHelper.getString( BYTECODE_PROVIDER, properties, BYTECODE_PROVIDER_NAME_DEFAULT );
return buildBytecodeProvider( provider );
return BytecodeProviderInitiator.buildBytecodeProvider( provider );
}

private static BytecodeProvider buildBytecodeProvider(String providerName) {
if ( BYTECODE_PROVIDER_NAME_NONE.equals( providerName ) ) {
return new org.hibernate.bytecode.internal.none.BytecodeProviderImpl();
}
if ( BYTECODE_PROVIDER_NAME_BYTEBUDDY.equals( providerName ) ) {
return new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl();
}

LOG.bytecodeProvider( providerName );

// there is no need to support plugging in a custom BytecodeProvider via FQCN:
// - the static helper methods on this class are deprecated
// - it's possible to plug a custom BytecodeProvider directly into the ServiceRegistry
//
// This also allows integrators to inject a BytecodeProvider instance which has some
// state; particularly useful to inject proxy definitions which have been prepared in
// advance.
// See also https://hibernate.atlassian.net/browse/HHH-13804 and how this was solved in
// Quarkus.

LOG.unknownBytecodeProvider( providerName, BYTECODE_PROVIDER_NAME_DEFAULT );
return new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1290,7 +1290,7 @@ void unableToWriteCachedFile(
void unexpectedRowCounts();

@LogMessage(level = WARN)
@Message(value = "unrecognized bytecode provider [%s], using [%s] by default", id = 382)
@Message(value = "Unrecognized bytecode provider [%s]; using the default implementation [%s]", id = 382)
void unknownBytecodeProvider(String providerName, String defaultProvider);

@LogMessage(level = WARN)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
package org.hibernate.jpa.internal.enhance;

import java.security.ProtectionDomain;
import java.util.Objects;

import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import org.hibernate.bytecode.enhance.spi.EnhancementContextWrapper;
import org.hibernate.bytecode.enhance.spi.Enhancer;
import org.hibernate.bytecode.internal.BytecodeProviderInitiator;
import org.hibernate.bytecode.spi.BytecodeProvider;
import org.hibernate.bytecode.spi.ClassTransformer;
import org.hibernate.cfg.Environment;

Expand All @@ -23,9 +26,12 @@
public class EnhancingClassTransformerImpl implements ClassTransformer {

private final EnhancementContext enhancementContext;
private final BytecodeProvider bytecodeProvider;

public EnhancingClassTransformerImpl(EnhancementContext enhancementContext) {
Copy link
Member

@yrodiere yrodiere Jan 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is something weird going on.

This constructor is only ever called from here:

@Override
public void pushClassTransformer(EnhancementContext enhancementContext) {
persistenceUnitInfo.addTransformer( new EnhancingClassTransformerImpl( enhancementContext ) );
}

But then all implementations of PersistenceUnitInfo#addTransformer are no-ops...

This component is probably not being tested. I'd suggest trying your patch in WildFly before merging?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, yes WildFly has a similar implementation but it's a different one.

Objects.requireNonNull( enhancementContext );
this.enhancementContext = enhancementContext;
this.bytecodeProvider = BytecodeProviderInitiator.buildDefaultBytecodeProvider();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't that possibly introducing another problem? You won't be using the same bytecode provider as Hibernate ORM...

But I must admit I don't know what this class is used for anyway :/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used by JPA's "enhance at deployment time" capability, used on EE servers.

And yes I'd like to make the BytecodeProvider implementation pluggable, but it really isn't today: choices are exclusively bytebuddy or none. Clearly this use case can't use none.

(there are other areas too in which it's implied that it needs to be the ByteBuddy one - I'd certainly like to improve that but I'm considering that a different issue)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And yes I'd like to make the BytecodeProvider implementation pluggable

I was thinking more that you're not using the same instance of BytecodeProvider, whereas before this patch, you were. I have no idea what kind of impact this can have, but since the bytecode provider is stateful, it might be a problem?

}

@Override
Expand All @@ -41,12 +47,15 @@ public byte[] transform(
// It also assumed that all calls come from the same class loader, which is fair, but this makes it more robust.

try {
Enhancer enhancer = Environment.getBytecodeProvider().getEnhancer( new EnhancementContextWrapper( enhancementContext, loader ) );
Enhancer enhancer = bytecodeProvider.getEnhancer( new EnhancementContextWrapper( enhancementContext, loader ) );
return enhancer.enhance( className, classfileBuffer );
}
catch (final Exception e) {
throw new TransformerException( "Error performing enhancement of " + className, e );
}
finally {
bytecodeProvider.resetCaches();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@

import org.hibernate.HibernateException;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.bytecode.spi.BytecodeProvider;
import org.hibernate.bytecode.spi.ProxyFactoryFactory;
import org.hibernate.bytecode.spi.ReflectionOptimizer;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.mapping.Backref;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.IndexBackref;
Expand All @@ -33,6 +32,7 @@
import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.property.access.spi.PropertyAccessStrategy;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
import org.hibernate.type.internal.CompositeUserTypeJavaTypeWrapper;
Expand Down Expand Up @@ -187,8 +187,9 @@ private ReflectionOptimizer buildReflectionOptimizer(
propertyAccessMap.put( property.getName(), getPropertyAccesses()[i] );
i++;
}
final BytecodeProvider bytecodeProvider = creationContext.getServiceRegistry().getService( BytecodeProvider.class );

return Environment.getBytecodeProvider().getReflectionOptimizer(
return bytecodeProvider.getReflectionOptimizer(
bootDescriptor.getComponentClass(),
propertyAccessMap
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.hibernate.bytecode.spi.ReflectionOptimizer.InstantiationOptimizer;
import org.hibernate.cfg.Environment;
import org.hibernate.classic.Lifecycle;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
Expand Down Expand Up @@ -140,8 +139,7 @@ else if ( bootDescriptorIdentifier != null ) {
identifierPropertyAccess = makePropertyAccess( identifierProperty );
}

// final BytecodeProvider bytecodeProvider = creationContext.getBootstrapContext().getBytecodeProvider();
final BytecodeProvider bytecodeProvider = Environment.getBytecodeProvider();
final BytecodeProvider bytecodeProvider = creationContext.getBootstrapContext().getServiceRegistry().getService( BytecodeProvider.class );

final EntityMetamodel entityMetamodel = runtimeDescriptor.getEntityMetamodel();
ProxyFactory proxyFactory = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,15 +265,16 @@ public final void initializeWithoutLoadIfPossible() {
/**
* Initialize internal state based on the currently attached session,
* in order to be ready to load data even after the proxy is detached from the session.
*
* This method only has any effect if
* {@link SessionFactoryOptions#isInitializeLazyStateOutsideTransactionsEnabled()} is {@code true}.
*/
protected void prepareForPossibleLoadingOutsideTransaction() {
if ( session != null ) {
allowLoadOutsideTransaction = session.getFactory().getSessionFactoryOptions().isInitializeLazyStateOutsideTransactionsEnabled();

if ( allowLoadOutsideTransaction && sessionFactoryUuid == null ) {
if ( sessionFactoryUuid == null ) {
//we're going to need the UUID even if we the SessionFactory configuration doesn't
// allow any operations on it, as we need it to match deserialized objects with
// the originating SessionFactory: at very least it's useful to actually get
// such configuration, so to know if such operation isn't allowed or configured otherwise.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you've changed the purpose of this method; maybe it should be renamed?

I don't know if this class is API or "looks like API but actually is not", though...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I've amended the javadoc to clarify.

sessionFactoryUuid = session.getFactory().getUuid();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public abstract class AbstractSerializableProxy implements Serializable {
private final String entityName;
private final Object id;
private final Boolean readOnly;
private final String sessionFactoryUuid;
protected final String sessionFactoryUuid;
private final boolean allowLoadOutsideTransaction;

protected AbstractSerializableProxy(
Expand Down
Loading