Save This Page
Home » cglib-src-2.2 » net.sf.cglib.core » [javadoc | source]
    1   /*
    2    * Copyright 2003,2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    *  Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   
   17   package net.sf.cglib.core;
   18   
   19   import java.lang.reflect.Method;
   20   import org.objectweb.asm.ClassVisitor;
   21   import org.objectweb.asm.Label;
   22   import org.objectweb.asm.Type;
   23   
   24   /**
   25    * Generates classes to handle multi-valued keys, for use in things such as Maps and Sets.
   26    * Code for <code>equals</code> and <code>hashCode</code> methods follow the
   27    * the rules laid out in <i>Effective Java</i> by Joshua Bloch. 
   28    * <p>
   29    * To generate a <code>KeyFactory</code>, you need to supply an interface which
   30    * describes the structure of the key. The interface should have a
   31    * single method named <code>newInstance</code>, which returns an
   32    * <code>Object</code>. The arguments array can be
   33    * <i>anything</i>--Objects, primitive values, or single or
   34    * multi-dimension arrays of either. For example:
   35    * <p><pre>
   36    *     private interface IntStringKey {
   37    *         public Object newInstance(int i, String s);
   38    *     }
   39    * </pre><p>
   40    * Once you have made a <code>KeyFactory</code>, you generate a new key by calling
   41    * the <code>newInstance</code> method defined by your interface.
   42    * <p><pre>
   43    *     IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class);
   44    *     Object key1 = factory.newInstance(4, "Hello");
   45    *     Object key2 = factory.newInstance(4, "World");
   46    * </pre><p>
   47    * <b>Note:</b>
   48    * <code>hashCode</code> equality between two keys <code>key1</code> and <code>key2</code> is only guaranteed if
   49    * <code>key1.equals(key2)</code> <i>and</i> the keys were produced by the same factory.
   50    *
   51    * @version $Id: KeyFactory.java,v 1.26 2006/03/05 02:43:19 herbyderby Exp $
   52    */
   53   abstract public class KeyFactory {
   54       private static final Signature GET_NAME =
   55         TypeUtils.parseSignature("String getName()");
   56       private static final Signature GET_CLASS =
   57         TypeUtils.parseSignature("Class getClass()");
   58       private static final Signature HASH_CODE =
   59         TypeUtils.parseSignature("int hashCode()");
   60       private static final Signature EQUALS =
   61         TypeUtils.parseSignature("boolean equals(Object)");
   62       private static final Signature TO_STRING =
   63         TypeUtils.parseSignature("String toString()");
   64       private static final Signature APPEND_STRING =
   65         TypeUtils.parseSignature("StringBuffer append(String)");
   66       private static final Type KEY_FACTORY =
   67         TypeUtils.parseType("net.sf.cglib.core.KeyFactory");
   68       
   69       //generated numbers: 
   70       private final static int PRIMES[] = {
   71                  11,         73,        179,       331,
   72                 521,        787,       1213,      1823,
   73                2609,       3691,       5189,      7247,
   74               10037,      13931,      19289,     26627,
   75               36683,      50441,      69403,     95401,
   76              131129,     180179,     247501,    340057,
   77              467063,     641371,     880603,   1209107,
   78             1660097,    2279161,    3129011,   4295723,
   79             5897291,    8095873,   11114263,  15257791,
   80            20946017,   28754629,   39474179,  54189869,
   81            74391461,  102123817,  140194277, 192456917,
   82           264202273,  362693231,  497900099, 683510293,
   83           938313161, 1288102441, 1768288259  };
   84       
   85   
   86       public static final Customizer CLASS_BY_NAME = new Customizer() {
   87           public void customize(CodeEmitter e, Type type) {
   88               if (type.equals(Constants.TYPE_CLASS)) {
   89                   e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
   90               }
   91           }
   92       };
   93   
   94       public static final Customizer OBJECT_BY_CLASS = new Customizer() {
   95           public void customize(CodeEmitter e, Type type) {
   96               e.invoke_virtual(Constants.TYPE_OBJECT, GET_CLASS);
   97           }
   98       };
   99   
  100       protected KeyFactory() {
  101       }
  102   
  103       public static KeyFactory create(Class keyInterface) {
  104           return create(keyInterface, null);
  105       }
  106   
  107       public static KeyFactory create(Class keyInterface, Customizer customizer) {
  108           return create(keyInterface.getClassLoader(), keyInterface,  customizer);
  109       }
  110   
  111       public static KeyFactory create(ClassLoader loader, Class keyInterface, Customizer customizer) {
  112           Generator gen = new Generator();
  113           gen.setInterface(keyInterface);
  114           gen.setCustomizer(customizer);
  115           gen.setClassLoader(loader);
  116           return gen.create();
  117       }
  118   
  119       public static class Generator extends AbstractClassGenerator {
  120           private static final Source SOURCE = new Source(KeyFactory.class.getName());
  121           private Class keyInterface;
  122           private Customizer customizer;
  123           private int constant;
  124           private int multiplier;
  125   
  126           public Generator() {
  127               super(SOURCE);
  128           }
  129   
  130           protected ClassLoader getDefaultClassLoader() {
  131               return keyInterface.getClassLoader();
  132           }
  133   
  134           public void setCustomizer(Customizer customizer) {
  135               this.customizer = customizer;
  136           }
  137   
  138           public void setInterface(Class keyInterface) {
  139               this.keyInterface = keyInterface;
  140           }
  141   
  142           public KeyFactory create() {
  143               setNamePrefix(keyInterface.getName());
  144               return (KeyFactory)super.create(keyInterface.getName());
  145           }
  146   
  147           public void setHashConstant(int constant) {
  148               this.constant = constant;
  149           }
  150   
  151           public void setHashMultiplier(int multiplier) {
  152               this.multiplier = multiplier;
  153           }
  154   
  155           protected Object firstInstance(Class type) {
  156               return ReflectUtils.newInstance(type);
  157           }
  158   
  159           protected Object nextInstance(Object instance) {
  160               return instance;
  161           }
  162   
  163           public void generateClass(ClassVisitor v) {
  164               ClassEmitter ce = new ClassEmitter(v);
  165               
  166               Method newInstance = ReflectUtils.findNewInstance(keyInterface);
  167               if (!newInstance.getReturnType().equals(Object.class)) {
  168                   throw new IllegalArgumentException("newInstance method must return Object");
  169               }
  170   
  171               Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());
  172               ce.begin_class(Constants.V1_2,
  173                              Constants.ACC_PUBLIC,
  174                              getClassName(),
  175                              KEY_FACTORY,
  176                              new Type[]{ Type.getType(keyInterface) },
  177                              Constants.SOURCE_FILE);
  178               EmitUtils.null_constructor(ce);
  179               EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));
  180   
  181               int seed = 0;
  182               CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
  183                                               TypeUtils.parseConstructor(parameterTypes),
  184                                               null);
  185               e.load_this();
  186               e.super_invoke_constructor();
  187               e.load_this();
  188               for (int i = 0; i < parameterTypes.length; i++) {
  189                   seed += parameterTypes[i].hashCode();
  190                   ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL,
  191                                    getFieldName(i),
  192                                    parameterTypes[i],
  193                                    null);
  194                   e.dup();
  195                   e.load_arg(i);
  196                   e.putfield(getFieldName(i));
  197               }
  198               e.return_value();
  199               e.end_method();
  200               
  201               // hash code
  202               e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null);
  203               int hc = (constant != 0) ? constant : PRIMES[(int)(Math.abs(seed) % PRIMES.length)];
  204               int hm = (multiplier != 0) ? multiplier : PRIMES[(int)(Math.abs(seed * 13) % PRIMES.length)];
  205               e.push(hc);
  206               for (int i = 0; i < parameterTypes.length; i++) {
  207                   e.load_this();
  208                   e.getfield(getFieldName(i));
  209                   EmitUtils.hash_code(e, parameterTypes[i], hm, customizer);
  210               }
  211               e.return_value();
  212               e.end_method();
  213   
  214               // equals
  215               e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null);
  216               Label fail = e.make_label();
  217               e.load_arg(0);
  218               e.instance_of_this();
  219               e.if_jump(e.EQ, fail);
  220               for (int i = 0; i < parameterTypes.length; i++) {
  221                   e.load_this();
  222                   e.getfield(getFieldName(i));
  223                   e.load_arg(0);
  224                   e.checkcast_this();
  225                   e.getfield(getFieldName(i));
  226                   EmitUtils.not_equals(e, parameterTypes[i], fail, customizer);
  227               }
  228               e.push(1);
  229               e.return_value();
  230               e.mark(fail);
  231               e.push(0);
  232               e.return_value();
  233               e.end_method();
  234   
  235               // toString
  236               e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null);
  237               e.new_instance(Constants.TYPE_STRING_BUFFER);
  238               e.dup();
  239               e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
  240               for (int i = 0; i < parameterTypes.length; i++) {
  241                   if (i > 0) {
  242                       e.push(", ");
  243                       e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
  244                   }
  245                   e.load_this();
  246                   e.getfield(getFieldName(i));
  247                   EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizer);
  248               }
  249               e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
  250               e.return_value();
  251               e.end_method();
  252   
  253               ce.end_class();
  254           }
  255   
  256           private String getFieldName(int arg) {
  257               return "FIELD_" + arg;
  258           }
  259       }
  260   }

Save This Page
Home » cglib-src-2.2 » net.sf.cglib.core » [javadoc | source]