Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl Maven / Gradle / Ivy
/*
* 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.bytecode.internal.bytebuddy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.concurrent.Callable;
import net.bytebuddy.TypeCache;
import org.hibernate.HibernateException;
import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl;
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import org.hibernate.bytecode.enhance.spi.Enhancer;
import org.hibernate.bytecode.spi.BytecodeProvider;
import org.hibernate.bytecode.spi.ProxyFactoryFactory;
import org.hibernate.bytecode.spi.ReflectionOptimizer;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.NamingStrategy;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.scaffold.TypeValidation;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.MethodCall;
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.implementation.bytecode.assign.primitive.PrimitiveBoxingDelegate;
import net.bytebuddy.implementation.bytecode.assign.primitive.PrimitiveUnboxingDelegate;
import net.bytebuddy.implementation.bytecode.assign.reference.ReferenceTypeAwareAssigner;
import net.bytebuddy.jar.asm.MethodVisitor;
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.jar.asm.Type;
import net.bytebuddy.matcher.ElementMatchers;
public class BytecodeProviderImpl implements BytecodeProvider {
private final TypeCache FAST_CLASSES = new TypeCache.WithInlineExpunction(TypeCache.Sort.SOFT);
private final TypeCache BULK_ACCESSORS = new TypeCache.WithInlineExpunction(TypeCache.Sort.SOFT);
@Override
public ProxyFactoryFactory getProxyFactoryFactory() {
return new ProxyFactoryFactoryImpl();
}
@Override
public ReflectionOptimizer getReflectionOptimizer(
final Class clazz,
final String[] getterNames,
final String[] setterNames,
final Class[] types) {
final Method[] getters = new Method[getterNames.length];
final Method[] setters = new Method[setterNames.length];
findAccessors( clazz, getterNames, setterNames, types, getters, setters );
final Constructor constructor = findConstructor( clazz );
Class fastClass = FAST_CLASSES.findOrInsert( clazz.getClassLoader(), clazz.getName(), new Callable>() {
@Override
public Class call() throws Exception {
return new ByteBuddy()
.with(TypeValidation.DISABLED)
.with(new NamingStrategy.SuffixingRandom("HibernateInstantiator"))
.subclass(ReflectionOptimizer.InstantiationOptimizer.class)
.method(ElementMatchers.named("newInstance"))
.intercept(MethodCall.construct(constructor))
.make()
.load(clazz.getClassLoader())
.getLoaded();
}
}, FAST_CLASSES);
fastClass = FAST_CLASSES.insert( clazz.getClassLoader(), clazz.getName(), fastClass );
Class bulkAccessor = BULK_ACCESSORS.findOrInsert( clazz.getClassLoader(), clazz.getName(), new Callable>() {
@Override
public Class call() throws Exception {
return new ByteBuddy()
.with(TypeValidation.DISABLED)
.with(new NamingStrategy.SuffixingRandom("HibernateAccessOptimizer"))
.subclass(ReflectionOptimizer.AccessOptimizer.class)
.method(ElementMatchers.named("getPropertyValues"))
.intercept(new Implementation.Simple(new GetPropertyValues(clazz, getters)))
.method(ElementMatchers.named("setPropertyValues"))
.intercept(new Implementation.Simple(new SetPropertyValues(clazz, setters)))
.method(ElementMatchers.named("getPropertyNames"))
.intercept(MethodCall.call(new CloningPropertyCall(getterNames)))
.make()
.load(clazz.getClassLoader())
.getLoaded();
}
}, BULK_ACCESSORS);
try {
return new ReflectionOptimizerImpl(
(ReflectionOptimizer.InstantiationOptimizer) fastClass.newInstance(),
(ReflectionOptimizer.AccessOptimizer) bulkAccessor.newInstance()
);
}
catch (Exception exception) {
throw new HibernateException( exception );
}
}
private static class GetPropertyValues implements ByteCodeAppender {
private final Class clazz;
private final Method[] getters;
public GetPropertyValues(Class clazz, Method[] getters) {
this.clazz = clazz;
this.getters = getters;
}
@Override
public Size apply(
MethodVisitor methodVisitor,
Implementation.Context implementationContext,
MethodDescription instrumentedMethod) {
methodVisitor.visitLdcInsn( getters.length );
methodVisitor.visitTypeInsn( Opcodes.ANEWARRAY, Type.getInternalName( Object.class ) );
int index = 0;
for ( Method getter : getters ) {
methodVisitor.visitInsn( Opcodes.DUP );
methodVisitor.visitLdcInsn( index++ );
methodVisitor.visitVarInsn( Opcodes.ALOAD, 1 );
methodVisitor.visitTypeInsn( Opcodes.CHECKCAST, Type.getInternalName( clazz ) );
methodVisitor.visitMethodInsn(
Opcodes.INVOKEVIRTUAL,
Type.getInternalName( clazz ),
getter.getName(),
Type.getMethodDescriptor( getter ),
false
);
if ( getter.getReturnType().isPrimitive() ) {
PrimitiveBoxingDelegate.forPrimitive( new TypeDescription.ForLoadedType( getter.getReturnType() ) )
.assignBoxedTo(
TypeDescription.Generic.OBJECT,
ReferenceTypeAwareAssigner.INSTANCE,
Assigner.Typing.STATIC
)
.apply( methodVisitor, implementationContext );
}
methodVisitor.visitInsn( Opcodes.AASTORE );
}
methodVisitor.visitInsn( Opcodes.ARETURN );
return new Size( 6, instrumentedMethod.getStackSize() );
}
}
private static class SetPropertyValues implements ByteCodeAppender {
private final Class clazz;
private final Method[] setters;
public SetPropertyValues(Class clazz, Method[] setters) {
this.clazz = clazz;
this.setters = setters;
}
@Override
public Size apply(
MethodVisitor methodVisitor,
Implementation.Context implementationContext,
MethodDescription instrumentedMethod) {
int index = 0;
for ( Method setter : setters ) {
methodVisitor.visitVarInsn( Opcodes.ALOAD, 1 );
methodVisitor.visitTypeInsn( Opcodes.CHECKCAST, Type.getInternalName( clazz ) );
methodVisitor.visitVarInsn( Opcodes.ALOAD, 2 );
methodVisitor.visitLdcInsn( index++ );
methodVisitor.visitInsn( Opcodes.AALOAD );
if ( setter.getParameterTypes()[0].isPrimitive() ) {
PrimitiveUnboxingDelegate.forReferenceType( TypeDescription.Generic.OBJECT )
.assignUnboxedTo(
new TypeDescription.Generic.OfNonGenericType.ForLoadedType( setter.getParameterTypes()[0] ),
ReferenceTypeAwareAssigner.INSTANCE,
Assigner.Typing.DYNAMIC
)
.apply( methodVisitor, implementationContext );
}
else {
methodVisitor.visitTypeInsn( Opcodes.CHECKCAST, Type.getInternalName( setter.getParameterTypes()[0] ) );
}
methodVisitor.visitMethodInsn(
Opcodes.INVOKEVIRTUAL,
Type.getInternalName( clazz ),
setter.getName(),
Type.getMethodDescriptor( setter ),
false
);
}
methodVisitor.visitInsn( Opcodes.RETURN );
return new Size( 4, instrumentedMethod.getStackSize() );
}
}
private static void findAccessors(
Class clazz,
String[] getterNames,
String[] setterNames,
Class[] types,
Method[] getters,
Method[] setters) {
final int length = types.length;
if ( setterNames.length != length || getterNames.length != length ) {
throw new BulkAccessorException( "bad number of accessors" );
}
final Class[] getParam = new Class[0];
final Class[] setParam = new Class[1];
for ( int i = 0; i < length; i++ ) {
if ( getterNames[i] != null ) {
final Method getter = findAccessor( clazz, getterNames[i], getParam, i );
if ( getter.getReturnType() != types[i] ) {
throw new BulkAccessorException( "wrong return type: " + getterNames[i], i );
}
getters[i] = getter;
}
if ( setterNames[i] != null ) {
setParam[0] = types[i];
setters[i] = findAccessor( clazz, setterNames[i], setParam, i );
}
}
}
@SuppressWarnings("unchecked")
private static Method findAccessor(Class clazz, String name, Class[] params, int index)
throws BulkAccessorException {
try {
final Method method = clazz.getDeclaredMethod( name, params );
if ( Modifier.isPrivate( method.getModifiers() ) ) {
throw new BulkAccessorException( "private property", index );
}
return method;
}
catch (NoSuchMethodException e) {
throw new BulkAccessorException( "cannot find an accessor", index );
}
}
private static Constructor findConstructor(Class clazz) {
try {
return clazz.getDeclaredConstructor();
}
catch (NoSuchMethodException e) {
throw new HibernateException( e );
}
}
public static class CloningPropertyCall implements Callable {
private final String[] propertyNames;
private CloningPropertyCall(String[] propertyNames) {
this.propertyNames = propertyNames;
}
@Override
public String[] call() {
return propertyNames.clone();
}
}
@Override
public Enhancer getEnhancer(EnhancementContext enhancementContext) {
return new EnhancerImpl( enhancementContext );
}
}