Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   * Copyright 2010 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
  * 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.
 import java.util.List;
 import java.util.Map;
 import  org.apache.bcel.Constants;
 import  org.apache.bcel.classfile.Constant;
 import  org.apache.bcel.classfile.JavaClass;
 import  org.apache.bcel.classfile.Visitor;
 import  org.apache.bcel.generic.ClassGen;
 import  org.apache.bcel.generic.ConstantPoolGen;
 import  org.apache.bcel.util.ClassLoaderRepository;

Used internally to manufacture test-classes with customized behaviour. A template class and a suitable parent class-loader is supplied to the static factory method newBuilder(ClassLoader,Class). A class is manufactured by retrieving the byte-code of the template-class and modify it step-by-step with the methods setNewClassName(String) and applyVisitor(Visitor) until the method wrapClass() is called to retrieve a ClassWrapper instance around the manufactured class. This is a fairly simple way to manufacture new classes through byte-code engineering but it fits very well when trying to make this framework work well together with other JUnit-integrating test-frameworks. The normal usage is to have template classes which extend JUnit API-classes with callback-params functionality. By modifying the template's super-class, so that it instead extends some other framework's JUnit API-extension, it is possible to mix the callback functionality with some other JUnit-integrating framework. This all seems to work fairly well for integrating with JUnit-extensions that offer mock-functionality or supply proper context for integration tests. However, integration with frameworks that offer parameterized testing does probably not work since their functionality is likely to clash with the parameterized functionality of this framework. In order for this factory to work well it is necessary that it deals with fairly simple template-classes who does not themselves provide any API that other classes need to know about. E.g. it won't do for the template-class to have any nested classes, since a nested class keep a reference to their outer class.

Henrik Kaipe
 public class TemplateBasedClassBuilder {
     private static class CustomizedClassLoader extends ClassLoader {
         final Map classToByteCode = new HashMap();
         private final ResourceMap builtResources = new ResourceMap();
         CustomizedClassLoader(ClassLoader parent) {
         Class newClass(final String classNamefinal JavaClass byteCode) {
             final byte[] bytes = byteCode.getBytes();
             Class newClass = defineClass(
                     classNamebytes, 0, bytes.length);
             return newClass;
         public URL getResource(String name) {
             URL url = .getURL(name);
             if (null != url) {
                 return url;
             } else {
                 return super.getResource(name);
         public InputStream getResourceAsStream(String name) {
             InputStream is = .getAsStream(name);
             if (null != is) {
                 return is;
             } else {
                 return super.getResourceAsStream(name);
    private final Class templateClass;
    private String newClassName;
    private List visitors = new ArrayList();
    private TemplateBasedClassBuilder(ClassLoader parentClass templateClass) {
        this. = new CustomizedClassLoader(parent);
        this. = templateClass;
The factory method to use for creating a new and initiated instance of TemplateBasedClassBuilder.
    public static TemplateBasedClassBuilder newBuilder(
            ClassLoader parentClass templateClass) {
        return new TemplateBasedClassBuilder(parenttemplateClass).reset();

Resets everything and starts-over again with the original byte-code of the template-class.

this instance
    public TemplateBasedClassBuilder reset() {
        this. = .getName();
        return this;


this instance
    public TemplateBasedClassBuilder setNewClassName(String newClassName) {
        this..add(new ClassConstantModifyingVisitor(
                .getName(), newClassName));
        this. = newClassName;
        return this;


visitor will be applied to the constants of the class byte-code
this instance
    public TemplateBasedClassBuilder applyVisitor(Visitor visitor) {
        return this;
    public ClassWrapper wrapClass() {
        return wrapClass(false);
    public ClassWrapper wrapClass(boolean abstractClass) {
        ClassGen cg = new ClassGen(retrieveJavaClass(
                .getParent(), ));
        ConstantPoolGen constantPool = cg.getConstantPool();
        final int poolSize = constantPool.getSize();
        for (Iterator iter = this..iterator() ; iter.hasNext() ;) {
            final Visitor visitor = (Visitor);
            for (int i = 0 ; i < poolSize ; ++i) {
                Constant constant = constantPool.getConstant(i);
                if (null != constant) {
                ? (Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT)
                : Constants.ACC_PUBLIC);
        return new ClassWrapper(this..newClass(
    private static JavaClass retrieveJavaClass(
            ClassLoader loaderClass templateClass) {
        if (loader instanceof CustomizedClassLoader) {
            Map byteCodeMap = ((CustomizedClassLoader)loader).;
            if (byteCodeMap.containsKey(templateClass)) {
                return (JavaClass) byteCodeMap.get(templateClass);
            } else {
                return retrieveJavaClass(loader.getParent(), templateClass);
        } else {
            try {
                return new ClassLoaderRepository(loader)
            } catch (ClassNotFoundException x) {
                throw new Error("It is vital that the template-class is visible"
                        +" from the specified parent ClassLoader instance."x);
New to GrepCode? Check out our FAQ X