CglibProxyFactory.java
- /*
- * Copyright 2009-2024 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.ibatis.executor.loader.cglib;
- import java.lang.reflect.Method;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.concurrent.locks.ReentrantLock;
- import net.sf.cglib.proxy.Callback;
- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- import org.apache.ibatis.executor.loader.AbstractEnhancedDeserializationProxy;
- import org.apache.ibatis.executor.loader.AbstractSerialStateHolder;
- import org.apache.ibatis.executor.loader.ProxyFactory;
- import org.apache.ibatis.executor.loader.ResultLoaderMap;
- import org.apache.ibatis.executor.loader.WriteReplaceInterface;
- import org.apache.ibatis.io.Resources;
- import org.apache.ibatis.logging.Log;
- import org.apache.ibatis.logging.LogFactory;
- import org.apache.ibatis.reflection.ExceptionUtil;
- import org.apache.ibatis.reflection.factory.ObjectFactory;
- import org.apache.ibatis.reflection.property.PropertyCopier;
- import org.apache.ibatis.reflection.property.PropertyNamer;
- import org.apache.ibatis.session.Configuration;
- /**
- * @author Clinton Begin
- *
- * @deprecated Since 3.5.10, use Javassist instead.
- */
- @Deprecated
- public class CglibProxyFactory implements ProxyFactory {
- private static final String FINALIZE_METHOD = "finalize";
- private static final String WRITE_REPLACE_METHOD = "writeReplace";
- public CglibProxyFactory() {
- try {
- Resources.classForName("net.sf.cglib.proxy.Enhancer");
- } catch (Throwable e) {
- throw new IllegalStateException(
- "Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.", e);
- }
- }
- @Override
- public Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration,
- ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
- return EnhancedResultObjectProxyImpl.createProxy(target, lazyLoader, configuration, objectFactory,
- constructorArgTypes, constructorArgs);
- }
- public Object createDeserializationProxy(Object target, Map<String, ResultLoaderMap.LoadPair> unloadedProperties,
- ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
- return EnhancedDeserializationProxyImpl.createProxy(target, unloadedProperties, objectFactory, constructorArgTypes,
- constructorArgs);
- }
- static Object createStaticProxy(Class<?> type, Callback callback, List<Class<?>> constructorArgTypes,
- List<Object> constructorArgs) {
- LogHolder.log.warn("CglibProxyFactory is deprecated. Use another proxy factory implementation.");
- Enhancer enhancer = new Enhancer();
- enhancer.setCallback(callback);
- enhancer.setSuperclass(type);
- try {
- type.getDeclaredMethod(WRITE_REPLACE_METHOD);
- // ObjectOutputStream will call writeReplace of objects returned by writeReplace
- if (LogHolder.log.isDebugEnabled()) {
- LogHolder.log.debug(WRITE_REPLACE_METHOD + " method was found on bean " + type + ", make sure it returns this");
- }
- } catch (NoSuchMethodException e) {
- enhancer.setInterfaces(new Class[] { WriteReplaceInterface.class });
- } catch (SecurityException e) {
- // nothing to do here
- }
- Object enhanced;
- if (constructorArgTypes.isEmpty()) {
- enhanced = enhancer.create();
- } else {
- Class<?>[] typesArray = constructorArgTypes.toArray(new Class[constructorArgTypes.size()]);
- Object[] valuesArray = constructorArgs.toArray(new Object[constructorArgs.size()]);
- enhanced = enhancer.create(typesArray, valuesArray);
- }
- return enhanced;
- }
- private static class EnhancedResultObjectProxyImpl implements MethodInterceptor {
- private final Class<?> type;
- private final ResultLoaderMap lazyLoader;
- private final boolean aggressive;
- private final Set<String> lazyLoadTriggerMethods;
- private final ObjectFactory objectFactory;
- private final List<Class<?>> constructorArgTypes;
- private final List<Object> constructorArgs;
- private final ReentrantLock lock = new ReentrantLock();
- private EnhancedResultObjectProxyImpl(Class<?> type, ResultLoaderMap lazyLoader, Configuration configuration,
- ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
- this.type = type;
- this.lazyLoader = lazyLoader;
- this.aggressive = configuration.isAggressiveLazyLoading();
- this.lazyLoadTriggerMethods = configuration.getLazyLoadTriggerMethods();
- this.objectFactory = objectFactory;
- this.constructorArgTypes = constructorArgTypes;
- this.constructorArgs = constructorArgs;
- }
- public static Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration,
- ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
- final Class<?> type = target.getClass();
- EnhancedResultObjectProxyImpl callback = new EnhancedResultObjectProxyImpl(type, lazyLoader, configuration,
- objectFactory, constructorArgTypes, constructorArgs);
- Object enhanced = createStaticProxy(type, callback, constructorArgTypes, constructorArgs);
- PropertyCopier.copyBeanProperties(type, target, enhanced);
- return enhanced;
- }
- @Override
- public Object intercept(Object enhanced, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- final String methodName = method.getName();
- lock.lock();
- try {
- if (WRITE_REPLACE_METHOD.equals(methodName)) {
- Object original;
- if (constructorArgTypes.isEmpty()) {
- original = objectFactory.create(type);
- } else {
- original = objectFactory.create(type, constructorArgTypes, constructorArgs);
- }
- PropertyCopier.copyBeanProperties(type, enhanced, original);
- if (lazyLoader.size() > 0) {
- return new CglibSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes,
- constructorArgs);
- } else {
- return original;
- }
- }
- if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
- if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {
- lazyLoader.loadAll();
- } else if (PropertyNamer.isSetter(methodName)) {
- final String property = PropertyNamer.methodToProperty(methodName);
- lazyLoader.remove(property);
- } else if (PropertyNamer.isGetter(methodName)) {
- final String property = PropertyNamer.methodToProperty(methodName);
- if (lazyLoader.hasLoader(property)) {
- lazyLoader.load(property);
- }
- }
- }
- return methodProxy.invokeSuper(enhanced, args);
- } catch (Throwable t) {
- throw ExceptionUtil.unwrapThrowable(t);
- } finally {
- lock.unlock();
- }
- }
- }
- private static class EnhancedDeserializationProxyImpl extends AbstractEnhancedDeserializationProxy
- implements MethodInterceptor {
- private EnhancedDeserializationProxyImpl(Class<?> type, Map<String, ResultLoaderMap.LoadPair> unloadedProperties,
- ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
- super(type, unloadedProperties, objectFactory, constructorArgTypes, constructorArgs);
- }
- public static Object createProxy(Object target, Map<String, ResultLoaderMap.LoadPair> unloadedProperties,
- ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
- final Class<?> type = target.getClass();
- EnhancedDeserializationProxyImpl callback = new EnhancedDeserializationProxyImpl(type, unloadedProperties,
- objectFactory, constructorArgTypes, constructorArgs);
- Object enhanced = createStaticProxy(type, callback, constructorArgTypes, constructorArgs);
- PropertyCopier.copyBeanProperties(type, target, enhanced);
- return enhanced;
- }
- @Override
- public Object intercept(Object enhanced, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- final Object o = super.invoke(enhanced, method, args);
- return o instanceof AbstractSerialStateHolder ? o : methodProxy.invokeSuper(o, args);
- }
- @Override
- protected AbstractSerialStateHolder newSerialStateHolder(Object userBean,
- Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory,
- List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
- return new CglibSerialStateHolder(userBean, unloadedProperties, objectFactory, constructorArgTypes,
- constructorArgs);
- }
- }
- private static class LogHolder {
- private static final Log log = LogFactory.getLog(CglibProxyFactory.class);
- }
- }