001/*
002 * Copyright 2003,2004 The Apache Software Foundation
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
019import java.lang.reflect.Method;
020import java.security.ProtectionDomain;
021import java.util.Collections;
022import java.util.List;
023
024import org.springframework.asm.ClassVisitor;
025import org.springframework.asm.Label;
026import org.springframework.asm.Type;
027import org.springframework.cglib.core.internal.CustomizerRegistry;
028
029/**
030 * Generates classes to handle multi-valued keys, for use in things such as Maps and Sets.
031 * Code for <code>equals</code> and <code>hashCode</code> methods follow the
032 * the rules laid out in <i>Effective Java</i> by Joshua Bloch.
033 * <p>
034 * To generate a <code>KeyFactory</code>, you need to supply an interface which
035 * describes the structure of the key. The interface should have a
036 * single method named <code>newInstance</code>, which returns an
037 * <code>Object</code>. The arguments array can be
038 * <i>anything</i>--Objects, primitive values, or single or
039 * multi-dimension arrays of either. For example:
040 * <p><pre>
041 *     private interface IntStringKey {
042 *         public Object newInstance(int i, String s);
043 *     }
044 * </pre><p>
045 * Once you have made a <code>KeyFactory</code>, you generate a new key by calling
046 * the <code>newInstance</code> method defined by your interface.
047 * <p><pre>
048 *     IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class);
049 *     Object key1 = factory.newInstance(4, "Hello");
050 *     Object key2 = factory.newInstance(4, "World");
051 * </pre><p>
052 * <b>Note:</b>
053 * <code>hashCode</code> equality between two keys <code>key1</code> and <code>key2</code> is only guaranteed if
054 * <code>key1.equals(key2)</code> <i>and</i> the keys were produced by the same factory.
055 * @version $Id: KeyFactory.java,v 1.26 2006/03/05 02:43:19 herbyderby Exp $
056 */
057@SuppressWarnings({"rawtypes", "unchecked"})
058abstract public class KeyFactory {
059
060        private static final Signature GET_NAME =
061                        TypeUtils.parseSignature("String getName()");
062
063        private static final Signature GET_CLASS =
064                        TypeUtils.parseSignature("Class getClass()");
065
066        private static final Signature HASH_CODE =
067                        TypeUtils.parseSignature("int hashCode()");
068
069        private static final Signature EQUALS =
070                        TypeUtils.parseSignature("boolean equals(Object)");
071
072        private static final Signature TO_STRING =
073                        TypeUtils.parseSignature("String toString()");
074
075        private static final Signature APPEND_STRING =
076                        TypeUtils.parseSignature("StringBuffer append(String)");
077
078        private static final Type KEY_FACTORY =
079                        TypeUtils.parseType("org.springframework.cglib.core.KeyFactory");
080
081        private static final Signature GET_SORT =
082                        TypeUtils.parseSignature("int getSort()");
083
084        //generated numbers:
085        private final static int PRIMES[] = {
086                        11, 73, 179, 331,
087                        521, 787, 1213, 1823,
088                        2609, 3691, 5189, 7247,
089                        10037, 13931, 19289, 26627,
090                        36683, 50441, 69403, 95401,
091                        131129, 180179, 247501, 340057,
092                        467063, 641371, 880603, 1209107,
093                        1660097, 2279161, 3129011, 4295723,
094                        5897291, 8095873, 11114263, 15257791,
095                        20946017, 28754629, 39474179, 54189869,
096                        74391461, 102123817, 140194277, 192456917,
097                        264202273, 362693231, 497900099, 683510293,
098                        938313161, 1288102441, 1768288259};
099
100
101        public static final Customizer CLASS_BY_NAME = new Customizer() {
102                public void customize(CodeEmitter e, Type type) {
103                        if (type.equals(Constants.TYPE_CLASS)) {
104                                e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
105                        }
106                }
107        };
108
109        public static final FieldTypeCustomizer STORE_CLASS_AS_STRING = new FieldTypeCustomizer() {
110                public void customize(CodeEmitter e, int index, Type type) {
111                        if (type.equals(Constants.TYPE_CLASS)) {
112                                e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
113                        }
114                }
115                public Type getOutType(int index, Type type) {
116                        if (type.equals(Constants.TYPE_CLASS)) {
117                                return Constants.TYPE_STRING;
118                        }
119                        return type;
120                }
121        };
122
123        /**
124         * {@link Type#hashCode()} is very expensive as it traverses full descriptor to calculate hash code.
125         * This customizer uses {@link Type#getSort()} as a hash code.
126         */
127        public static final HashCodeCustomizer HASH_ASM_TYPE = new HashCodeCustomizer() {
128                public boolean customize(CodeEmitter e, Type type) {
129                        if (Constants.TYPE_TYPE.equals(type)) {
130                                e.invoke_virtual(type, GET_SORT);
131                                return true;
132                        }
133                        return false;
134                }
135        };
136
137        /**
138         * @deprecated this customizer might result in unexpected class leak since key object still holds a strong reference to the Object and class.
139         * It is recommended to have pre-processing method that would strip Objects and represent Classes as Strings
140         */
141        @Deprecated
142        public static final Customizer OBJECT_BY_CLASS = new Customizer() {
143                public void customize(CodeEmitter e, Type type) {
144                        e.invoke_virtual(Constants.TYPE_OBJECT, GET_CLASS);
145                }
146        };
147
148        protected KeyFactory() {
149        }
150
151        public static KeyFactory create(Class keyInterface) {
152                return create(keyInterface, null);
153        }
154
155        public static KeyFactory create(Class keyInterface, Customizer customizer) {
156                return create(keyInterface.getClassLoader(), keyInterface, customizer);
157        }
158
159        public static KeyFactory create(Class keyInterface, KeyFactoryCustomizer first, List<KeyFactoryCustomizer> next) {
160                return create(keyInterface.getClassLoader(), keyInterface, first, next);
161        }
162
163        public static KeyFactory create(ClassLoader loader, Class keyInterface, Customizer customizer) {
164                return create(loader, keyInterface, customizer, Collections.<KeyFactoryCustomizer>emptyList());
165        }
166
167        public static KeyFactory create(ClassLoader loader, Class keyInterface, KeyFactoryCustomizer customizer,
168                        List<KeyFactoryCustomizer> next) {
169                Generator gen = new Generator();
170                gen.setInterface(keyInterface);
171                // SPRING PATCH BEGIN
172                gen.setContextClass(keyInterface);
173                // SPRING PATCH END
174
175                if (customizer != null) {
176                        gen.addCustomizer(customizer);
177                }
178                if (next != null && !next.isEmpty()) {
179                        for (KeyFactoryCustomizer keyFactoryCustomizer : next) {
180                                gen.addCustomizer(keyFactoryCustomizer);
181                        }
182                }
183                gen.setClassLoader(loader);
184                return gen.create();
185        }
186
187
188        public static class Generator extends AbstractClassGenerator {
189
190                private static final Source SOURCE = new Source(KeyFactory.class.getName());
191
192                private static final Class[] KNOWN_CUSTOMIZER_TYPES = new Class[]{Customizer.class, FieldTypeCustomizer.class};
193
194                private Class keyInterface;
195
196                // TODO: Make me final when deprecated methods are removed
197                private CustomizerRegistry customizers = new CustomizerRegistry(KNOWN_CUSTOMIZER_TYPES);
198
199                private int constant;
200
201                private int multiplier;
202
203                public Generator() {
204                        super(SOURCE);
205                }
206
207                protected ClassLoader getDefaultClassLoader() {
208                        return keyInterface.getClassLoader();
209                }
210
211                protected ProtectionDomain getProtectionDomain() {
212                        return ReflectUtils.getProtectionDomain(keyInterface);
213                }
214
215                /**
216                 * @deprecated Use {@link #addCustomizer(KeyFactoryCustomizer)} instead.
217                 */
218                @Deprecated
219                public void setCustomizer(Customizer customizer) {
220                        customizers = CustomizerRegistry.singleton(customizer);
221                }
222
223                public void addCustomizer(KeyFactoryCustomizer customizer) {
224                        customizers.add(customizer);
225                }
226
227                public <T> List<T> getCustomizers(Class<T> klass) {
228                        return customizers.get(klass);
229                }
230
231                public void setInterface(Class keyInterface) {
232                        this.keyInterface = keyInterface;
233                }
234
235                public KeyFactory create() {
236                        setNamePrefix(keyInterface.getName());
237                        return (KeyFactory) super.create(keyInterface.getName());
238                }
239
240                public void setHashConstant(int constant) {
241                        this.constant = constant;
242                }
243
244                public void setHashMultiplier(int multiplier) {
245                        this.multiplier = multiplier;
246                }
247
248                protected Object firstInstance(Class type) {
249                        return ReflectUtils.newInstance(type);
250                }
251
252                protected Object nextInstance(Object instance) {
253                        return instance;
254                }
255
256                public void generateClass(ClassVisitor v) {
257                        ClassEmitter ce = new ClassEmitter(v);
258
259                        Method newInstance = ReflectUtils.findNewInstance(keyInterface);
260                        if (!newInstance.getReturnType().equals(Object.class)) {
261                                throw new IllegalArgumentException("newInstance method must return Object");
262                        }
263
264                        Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());
265                        ce.begin_class(Constants.V1_8,
266                                        Constants.ACC_PUBLIC,
267                                        getClassName(),
268                                        KEY_FACTORY,
269                                        new Type[]{Type.getType(keyInterface)},
270                                        Constants.SOURCE_FILE);
271                        EmitUtils.null_constructor(ce);
272                        EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));
273
274                        int seed = 0;
275                        CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
276                                        TypeUtils.parseConstructor(parameterTypes),
277                                        null);
278                        e.load_this();
279                        e.super_invoke_constructor();
280                        e.load_this();
281                        List<FieldTypeCustomizer> fieldTypeCustomizers = getCustomizers(FieldTypeCustomizer.class);
282                        for (int i = 0; i < parameterTypes.length; i++) {
283                                Type parameterType = parameterTypes[i];
284                                Type fieldType = parameterType;
285                                for (FieldTypeCustomizer customizer : fieldTypeCustomizers) {
286                                        fieldType = customizer.getOutType(i, fieldType);
287                                }
288                                seed += fieldType.hashCode();
289                                ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL,
290                                                getFieldName(i),
291                                                fieldType,
292                                                null);
293                                e.dup();
294                                e.load_arg(i);
295                                for (FieldTypeCustomizer customizer : fieldTypeCustomizers) {
296                                        customizer.customize(e, i, parameterType);
297                                }
298                                e.putfield(getFieldName(i));
299                        }
300                        e.return_value();
301                        e.end_method();
302
303                        // hash code
304                        e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null);
305                        int hc = (constant != 0) ? constant : PRIMES[(Math.abs(seed) % PRIMES.length)];
                        int hm = (multiplier != 0) ? multiplier : PRIMES[(Math.abs(seed * 13) % PRIMES.length)];
307                        e.push(hc);
308                        for (int i = 0; i < parameterTypes.length; i++) {
309                                e.load_this();
310                                e.getfield(getFieldName(i));
311                                EmitUtils.hash_code(e, parameterTypes[i], hm, customizers);
312                        }
313                        e.return_value();
314                        e.end_method();
315
316                        // equals
317                        e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null);
318                        Label fail = e.make_label();
319                        e.load_arg(0);
320                        e.instance_of_this();
321                        e.if_jump(CodeEmitter.EQ, fail);
322                        for (int i = 0; i < parameterTypes.length; i++) {
323                                e.load_this();
324                                e.getfield(getFieldName(i));
325                                e.load_arg(0);
326                                e.checkcast_this();
327                                e.getfield(getFieldName(i));
328                                EmitUtils.not_equals(e, parameterTypes[i], fail, customizers);
329                        }
330                        e.push(1);
331                        e.return_value();
332                        e.mark(fail);
333                        e.push(0);
334                        e.return_value();
335                        e.end_method();
336
337                        // toString
338                        e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null);
339                        e.new_instance(Constants.TYPE_STRING_BUFFER);
340                        e.dup();
341                        e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
342                        for (int i = 0; i < parameterTypes.length; i++) {
343                                if (i > 0) {
344                                        e.push(", ");
345                                        e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
346                                }
347                                e.load_this();
348                                e.getfield(getFieldName(i));
349                                EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizers);
350                        }
351                        e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
352                        e.return_value();
353                        e.end_method();
354
355                        ce.end_class();
356                }
357
358                private String getFieldName(int arg) {
359                        return "FIELD_" + arg;
360                }
361        }
362
363}