/*
 * Copyright 2002-2018 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.springframework.instrument.classloading;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

ClassFileTransformer-based weaver, allowing for a list of transformers to be applied on a class byte array. Normally used inside class loaders.

Note: This class is deliberately implemented for minimal external dependencies, since it is included in weaver jars (to be deployed into application servers).

Author:Rod Johnson, Costin Leau, Juergen Hoeller
Since:2.0
/** * ClassFileTransformer-based weaver, allowing for a list of transformers to be * applied on a class byte array. Normally used inside class loaders. * * <p>Note: This class is deliberately implemented for minimal external dependencies, * since it is included in weaver jars (to be deployed into application servers). * * @author Rod Johnson * @author Costin Leau * @author Juergen Hoeller * @since 2.0 */
public class WeavingTransformer { @Nullable private final ClassLoader classLoader; private final List<ClassFileTransformer> transformers = new ArrayList<>();
Create a new WeavingTransformer for the given class loader.
Params:
  • classLoader – the ClassLoader to build a transformer for
/** * Create a new WeavingTransformer for the given class loader. * @param classLoader the ClassLoader to build a transformer for */
public WeavingTransformer(@Nullable ClassLoader classLoader) { this.classLoader = classLoader; }
Add a class file transformer to be applied by this weaver.
Params:
  • transformer – the class file transformer to register
/** * Add a class file transformer to be applied by this weaver. * @param transformer the class file transformer to register */
public void addTransformer(ClassFileTransformer transformer) { Assert.notNull(transformer, "Transformer must not be null"); this.transformers.add(transformer); }
Apply transformation on a given class byte definition. The method will always return a non-null byte array (if no transformation has taken place the array content will be identical to the original one).
Params:
  • className – the full qualified name of the class in dot format (i.e. some.package.SomeClass)
  • bytes – class byte definition
Returns:(possibly transformed) class byte definition
/** * Apply transformation on a given class byte definition. * The method will always return a non-null byte array (if no transformation has taken place * the array content will be identical to the original one). * @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass) * @param bytes class byte definition * @return (possibly transformed) class byte definition */
public byte[] transformIfNecessary(String className, byte[] bytes) { String internalName = StringUtils.replace(className, ".", "/"); return transformIfNecessary(className, internalName, bytes, null); }
Apply transformation on a given class byte definition. The method will always return a non-null byte array (if no transformation has taken place the array content will be identical to the original one).
Params:
  • className – the full qualified name of the class in dot format (i.e. some.package.SomeClass)
  • internalName – class name internal name in / format (i.e. some/package/SomeClass)
  • bytes – class byte definition
  • pd – protection domain to be used (can be null)
Returns:(possibly transformed) class byte definition
/** * Apply transformation on a given class byte definition. * The method will always return a non-null byte array (if no transformation has taken place * the array content will be identical to the original one). * @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass) * @param internalName class name internal name in / format (i.e. some/package/SomeClass) * @param bytes class byte definition * @param pd protection domain to be used (can be null) * @return (possibly transformed) class byte definition */
public byte[] transformIfNecessary(String className, String internalName, byte[] bytes, @Nullable ProtectionDomain pd) { byte[] result = bytes; for (ClassFileTransformer cft : this.transformers) { try { byte[] transformed = cft.transform(this.classLoader, internalName, null, pd, result); if (transformed != null) { result = transformed; } } catch (IllegalClassFormatException ex) { throw new IllegalStateException("Class file transformation failed", ex); } } return result; } }