001/*
002 * Copyright 2002-2019 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.cglib.core;
018
019/**
020 * CGLIB GeneratorStrategy variant which exposes the application ClassLoader
021 * as current thread context ClassLoader for the time of class generation.
022 * The ASM ClassWriter in Spring's ASM variant will pick it up when doing
023 * common superclass resolution.
024 *
025 * @author Juergen Hoeller
026 * @since 5.2
027 */
028public class ClassLoaderAwareGeneratorStrategy extends DefaultGeneratorStrategy {
029
030        private final ClassLoader classLoader;
031
032        public ClassLoaderAwareGeneratorStrategy(ClassLoader classLoader) {
033                this.classLoader = classLoader;
034        }
035
036        @Override
037        public byte[] generate(ClassGenerator cg) throws Exception {
038                if (this.classLoader == null) {
039                        return super.generate(cg);
040                }
041
042                Thread currentThread = Thread.currentThread();
043                ClassLoader threadContextClassLoader;
044                try {
045                        threadContextClassLoader = currentThread.getContextClassLoader();
046                }
047                catch (Throwable ex) {
048                        // Cannot access thread context ClassLoader - falling back...
049                        return super.generate(cg);
050                }
051
052                boolean overrideClassLoader = !this.classLoader.equals(threadContextClassLoader);
053                if (overrideClassLoader) {
054                        currentThread.setContextClassLoader(this.classLoader);
055                }
056                try {
057                        return super.generate(cg);
058                }
059                finally {
060                        if (overrideClassLoader) {
061                                // Reset original thread context ClassLoader.
062                                currentThread.setContextClassLoader(threadContextClassLoader);
063                        }
064                }
065        }
066
067}