svnno****@sourc*****
svnno****@sourc*****
2009年 3月 26日 (木) 20:42:07 JST
Revision: 2999 http://svn.sourceforge.jp/view?root=jiemamy&view=rev&rev=2999 Author: ashigeru Date: 2009-03-26 20:42:07 +0900 (Thu, 26 Mar 2009) Log Message: ----------- コードレビューのためにコメントを追加。 JavassistConverterに対応するテストを追加。 Modified Paths: -------------- leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/FactoryEnhancer.java leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/AccessibilityValidator.java leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/EmptyClassLoader.java leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/JavassistConverter.java leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/NewInstanceEnhancer.java Added Paths: ----------- leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/helper/JavassistConverterTest.java -------------- next part -------------- Modified: leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/FactoryEnhancer.java =================================================================== --- leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/FactoryEnhancer.java 2009-03-25 09:35:21 UTC (rev 2998) +++ leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/FactoryEnhancer.java 2009-03-26 11:42:07 UTC (rev 2999) @@ -331,7 +331,7 @@ private Class<? extends T> prepareEnhanced() throws EnhanceException { LOG.debug("Start factory enhancer: {}", factoryImplementation); - CtClass original = converter.toCtClass(factoryImplementation); + CtClass original = converter.loadCtClass(factoryImplementation); CtClass enhance = createCopyClass(original); AccessibilityValidator.validate(enhance); @@ -470,7 +470,7 @@ * それぞれのプロダクトクラスに対するメソッドアスペクトの一覧 * ({@code base -> aspect for each method}) * @return - * ファクトリに実際に埋め込まれるべきアスペクトの一覧 + * ファクトリに実際に埋め込まれるべきアスペクトの一覧、ひとつも存在しない場合は{@code null} * @throws EnhanceException 拡張に失敗した場合 * @see #testAllWeaveTargetWillBeEnhanced(Map, Map) */ @@ -532,7 +532,7 @@ * </p> * @param base 拡張される前のプロダクトクラス定義 * @param enhance 拡張対象となるプロダクトクラス定義 - * @return 対象のプロダクトクラスに適用すべきアスペクトの一覧 + * @return 対象のプロダクトクラスに適用すべきアスペクトの一覧、ひとつも存在しない場合は{@code null} * @throws EnhanceException * @see #weavePointcutIntoAllProducts(Map) */ Modified: leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/AccessibilityValidator.java =================================================================== --- leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/AccessibilityValidator.java 2009-03-25 09:35:21 UTC (rev 2998) +++ leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/AccessibilityValidator.java 2009-03-26 11:42:07 UTC (rev 2999) @@ -187,6 +187,7 @@ case ConstPool.CONST_Double: case ConstPool.CONST_Long: + // Double, Longはコンスタントプールを2スロット占有するため、次をスキップ index++; break; @@ -251,7 +252,8 @@ assert name != null; assert descriptor != null; if (name.equals(MethodInfo.nameClinit)) { - // class initializer is valid (void <clinit>(){ ...}) + // クラス初期化子は常に正当である + // void <init>() {...} という形式なので、常に参照解決できる } else if (name.equals(MethodInfo.nameInit)) { CtConstructor ref = loadConstructor(declaring, descriptor); @@ -622,7 +624,7 @@ * 参照可能であるメンバは、次の条件を満たすメンバである。 * </p> * <ul> - * <li> 参照元野方で宣言される </li> + * <li> 参照元の型で宣言される </li> * <li> {@code protected}で宣言され、かつ参照元のスーパータイプで宣言される </li> * <li> {@code public}で宣言される </li> * </ul> Modified: leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/EmptyClassLoader.java =================================================================== --- leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/EmptyClassLoader.java 2009-03-25 09:35:21 UTC (rev 2998) +++ leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/EmptyClassLoader.java 2009-03-26 11:42:07 UTC (rev 2999) @@ -16,17 +16,39 @@ package org.jiemamy.utils.enhancer.helper; /** - * 特別何も行わないクラスローダ。 + * 自身ではクラスをロードすることができないクラスローダ。 + * <p> + * このクラスローダは、外部から + * {@link #defineClass(String, byte[], int, int) ClassLoader.defineClass(*)} + * が呼び出されることを前提としている。 + * この分割により、次の利点が望める。 + * </p> + * <ul> + * <li> + * 動的に生成されたクラスを、通常のクラスローダ上にではなくこの{@link EmptyClassLoader}上に + * {@link #defineClass(String, byte[], int, int) 定義}させることができる。 + * これにより、通常のローダによるクラスの定義に影響することなく、動的生成されたクラスをロードすることができる。 + * </li> + * <li> + * クラスを動的に生成する機構ごとにこのローダの異なるインスタンスを与えることで、 + * それぞれの機構で生成されたクラスの定義が衝突することを防げる。 + * </li> + * <li> + * 動的に生成されたクラスがすべて不要となった場合、このローダをGCの対象とすることができる。 + * クラスローダがGCの対象となった場合、それによってロードされたクラスをアンロード(JVMS2-2.17.8) + * することができ、動的生成されたクラスによるメモリリークを防げる可能性がある。 + * </li> + * </ul> * @version $Date$ * @author Suguru ARAKAWA (Gluegent, Inc.) */ public class EmptyClassLoader extends ClassLoader { - - /** - * インスタンスを生成する。 - * @param parent 親クラスローダ - */ - public EmptyClassLoader(ClassLoader parent) { - super(parent); - } + + /** + * インスタンスを生成する。 + * @param parent 親クラスローダ + */ + public EmptyClassLoader(ClassLoader parent) { + super(parent); + } } Modified: leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/JavassistConverter.java =================================================================== --- leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/JavassistConverter.java 2009-03-25 09:35:21 UTC (rev 2998) +++ leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/JavassistConverter.java 2009-03-26 11:42:07 UTC (rev 2999) @@ -48,10 +48,15 @@ private static final Logger LOG = LoggerFactory.getLogger(JavassistConverter.class); + /** + * CtClassで表現されたプリミティブ型をjava.lang.Classで表現された同一の型に + * 変換するためのテーブル。 + */ private static final Map<CtClass, Class<?>> PRIMITIVES; static {{ Map<CtClass, Class<?>> map = new TreeMap<CtClass, Class<?>>(CtClassComparator.INSTANCE); + map.put(CtClass.voidType, void.class); map.put(CtClass.intType, int.class); map.put(CtClass.longType, long.class); map.put(CtClass.floatType, float.class); @@ -70,6 +75,14 @@ /** * インスタンスを生成する。 + * <p> + * 生成されたインスタンスを利用してロードされるクラスは、 + * {@code targetClass}の定義ローダ(JVMS2-5.3)を親ローダに持つような、 + * クラスローダによって定義またはロードされる。 + * そのクラスローダはこのクラスのインスタンスごとに新しく生成され、 + * このクラスの同一のインスタンスを利用してロードされるクラスは、 + * すべてこのインスタンスごとに生成されたクラスローダを利用する。 + * </p> * @param targetClass 基点とするクラス * @throws NullPointerException 引数に{@code null}が指定された場合 */ @@ -80,20 +93,54 @@ } this.pool = new ClassPool(); this.pool.appendClassPath(new ClassClassPath(targetClass)); + // targetClass.getClassLoader() をそのまま利用すると、 + // targetClassのリアルローダ上にエンハンスされたクラスが定義されてしまう。 + // これは、名前空間の衝突やクラスオブジェクトのリークの原因となる。 + // これを回避するため、エンハンサは自身ではクラスをロードしないEmptyClassLoaderを定義し、 + // その親ローダをtargetClassのリアルローダとする。 + // JavassistはEmptyClassLoader上のdefineClass(*)を呼び出すため、 + // エンハンスされたクラスはtargetClassのリアルローダ上ではなくEmptyClassLoader上で + // 定義されることになる。 + // @see javassist.ClassPool#toClass(ClassLoader, ProtectionDomain) this.loader = new EmptyClassLoader(targetClass.getClassLoader()); } + /** + * このインスタンスが利用する{@link ClassPool}を返す。 + * <p> + * 返されるインスタンスは、このインスタンスを生成する際にコンストラクタに渡したクラスの、 + * 定義ローダによってロード可能なすべてのクラスを参照することができる。 + * </p> + * @return このインスタンスが利用する{@link ClassPool} + */ + public ClassPool getClassPool() { + return this.pool; + } /** - * 指定の{@link java.lang.Class}オブジェクトを対応する{@link CtClass}に変換する。 - * @param klass 変換対象の{@link java.lang.Class}オブジェクト + * 指定の{@link java.lang.Class}オブジェクトに対応する{@link CtClass}をロードする。 + * <p> + * 指定する{@link java.lang.Class}は、次のすべてを満たす必要がある。 + * </p> + * <ul> + * <li> クラス、インターフェース、列挙、注釈型のいずれかである </li> + * <li> トップレベルの型宣言である </li> + * </ul> + * @param klass 対象の{@link java.lang.Class}オブジェクト * @return 対応する{@link CtClass} - * @throws EnhanceException 変換に失敗した場合 + * @throws NullPointerException 引数に{@code null}が指定された場合 + * @throws IllegalArgumentException {@link java.lang.Class}が不正である場合 + * @throws EnhanceException ロードに失敗した場合 */ - public CtClass toCtClass(Class<?> klass) throws EnhanceException { - assert klass != null; - assert klass.getCanonicalName() != null; + public CtClass loadCtClass(Class<?> klass) throws EnhanceException { + if (klass == null) { + throw new NullPointerException("klass"); //$NON-NLS-1$ + } + if (klass.isArray() || klass.isPrimitive() || klass.isMemberClass() || klass.isLocalClass() || klass.isAnonymousClass()) { + throw new IllegalArgumentException("klass"); //$NON-NLS-1$ + } String name = klass.getCanonicalName(); + assert name != null; try { return pool.get(name); } @@ -114,35 +161,45 @@ * </p> * @param klass 対象の{@link CtClass}オブジェクト * @return 対応する{@link java.lang.Class}オブジェクト + * @throws NullPointerException 引数に{@code null}が指定された場合 * @throws EnhanceException 変換に失敗した場合 */ public Class<?> toClass(CtClass klass) throws EnhanceException { - assert klass != null; + if (klass == null) { + throw new NullPointerException("klass"); //$NON-NLS-1$ + } LOG.trace("Loading java.lang.Class: {}", klass.getName()); try { if (klass.isPrimitive()) { + // プリミティブ型はクラスローダでロードできないため、別の処理を行う Class<?> prim = toPrimitiveClass(klass); assert prim != null; return prim; } else if (klass.isArray()) { + // 配列型もクラスローダでロードできないため、別の処理 CtClass current = klass; int dim = 0; while (current.isArray()) { dim++; current = current.getComponentType(); } + // ただし、要素型は先にロードされていないといけない Class<?> root = toClass(current); // FIXME to smart + // Class<T>からClass<T[]>を作る方法が不明なので、 + // 一度 Array.newInstance で T[] を作ってから getClass() して実現。 Object array = Array.newInstance(root, new int[dim]); return array.getClass(); } else { + // 親ローダでロードできたり、すでにロード済みのものがあればそれを利用 Class<?> loaded = findFromLoader(klass); if (loaded != null) { klass.freeze(); return loaded; } + // なければローダ上に定義する else { LOG.debug("Register to JVM: {}", klass.getName()); return klass.toClass( @@ -175,10 +232,13 @@ * </p> * @param classes 変換対象の一覧 * @return 対応する変換結果の一覧 + * @throws NullPointerException 引数に{@code null}が指定された場合 * @throws EnhanceException 変換に失敗した場合 */ public Class<?>[] toClasses(CtClass[] classes) throws EnhanceException { - assert classes != null; + if (classes == null) { + throw new NullPointerException("classes"); //$NON-NLS-1$ + } Class<?>[] results = new Class<?>[classes.length]; for (int i = 0; i < results.length; i++) { results[i] = toClass(classes[i]); @@ -197,9 +257,7 @@ assert klass != null; assert klass.isPrimitive(); Class<?> javaLangClass = PRIMITIVES.get(klass); - if (javaLangClass == null) { - throw new AssertionError("primitive ? " + klass); - } + assert javaLangClass != null : klass; return javaLangClass; } Modified: leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/NewInstanceEnhancer.java =================================================================== --- leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/NewInstanceEnhancer.java 2009-03-25 09:35:21 UTC (rev 2998) +++ leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/NewInstanceEnhancer.java 2009-03-26 11:42:07 UTC (rev 2999) @@ -15,9 +15,6 @@ */ package org.jiemamy.utils.enhancer.helper; -import static org.jiemamy.utils.enhancer.helper.EnhanceManipulator.createAdviceTableField; -import static org.jiemamy.utils.enhancer.helper.EnhanceManipulator.replaceToPointcut; - import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; @@ -67,7 +64,7 @@ * それぞれのプロダクトクラスに対するメソッドアスペクトの一覧 * ({@code base -> aspect for each method}) * @return - * ファクトリに実際に埋め込まれるべきアスペクトの一覧 + * ファクトリに実際に埋め込まれるべきアスペクトの一覧、ひとつも存在しない場合は{@code null} * @throws EnhanceException 拡張に失敗した場合 */ public static AspectList<CtConstructor> enhance(CtClass target, EnhanceManager enhanceManager, @@ -149,12 +146,16 @@ } CtClass declaring = constructor.getDeclaringClass(); List<InvocationHandler> handlers = enhanceManager.findApplicableHandlers(declaring, constructor); + + // 書き換えても挙動がまったく変化しないため、何も行わないで終了 if (handlers.isEmpty() && productEnhanceMap.containsKey(declaring) == false && allProductAspects.containsKey(declaring) == false) { return; } + + // 対象クラスに対する最初の拡張であれば、アドバイステーブルを作成 if (enhanceIndex == 0) { - holder = createAdviceTableField(target); + holder = EnhanceManipulator.createAdviceTableField(target); } LOG.debug("Rewrite new[{}]: {} (at {}{}:{})", new Object[] { @@ -165,14 +166,18 @@ expr.getLineNumber() }); - replaceToPointcut(expr, holder, enhanceIndex); + // new Hoge(...)の部分を、アドバイスの実行に置き換える + EnhanceManipulator.replaceToPointcut(expr, holder, enhanceIndex); if (productEnhanceMap.containsKey(declaring)) { + // newする対象のクラス自体がエンハンスされて別クラスになっている場合、 + // 呼び出し先のコンストラクタはエンハンス後のクラス上で定義されたものに変更 CtClass actual = productEnhanceMap.get(declaring); String descriptor = constructor.getSignature(); CtConstructor actualCtor = actual.getConstructor(descriptor); aspects.add(new Aspect<CtConstructor>(constructor, actualCtor, handlers)); } else { + // newする対象自体が同一である場合、呼び出し先のコンストラクタは変更なし assert allProductAspects.containsKey(declaring) == false; aspects.add(new Aspect<CtConstructor>(constructor, constructor, handlers)); } Added: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/helper/JavassistConverterTest.java =================================================================== --- leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/helper/JavassistConverterTest.java (rev 0) +++ leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/helper/JavassistConverterTest.java 2009-03-26 11:42:07 UTC (rev 2999) @@ -0,0 +1,238 @@ +/* + * Copyright 2007-2009 Jiemamy Project and the Others. + * Created on 2009/03/26 + * + * This file is part of Jiemamy. + * + * 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 + * + * http://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.jiemamy.utils.enhancer.helper; + +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.sameInstance; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import java.util.Map; +import java.util.concurrent.Callable; + +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtMethod; + +import org.junit.Test; + +/** + * Test for {@link JavassistConverter}. + * @author Suguru ARAKAWA + */ +public class JavassistConverterTest { + + /** + * Test method for {@link JavassistConverter#JavassistConverter(java.lang.Class)}. + * @throws Exception if occur + */ + @Test + public void testJavassistConverter() throws Exception { + JavassistConverter converter = new JavassistConverter(getClass()); + ClassPool pool = converter.getClassPool(); + CtClass example1 = pool.makeClass("Example1"); + CtClass example2 = pool.makeClass("Example2"); + + Class<?> created1 = converter.toClass(example1); + Class<?> created2 = converter.toClass(example2); + + assertThat(created1.getName(), is("Example1")); + assertThat(created2.getName(), is("Example2")); + + Class<?> self = Class.forName(getClass().getName(), false, created1.getClassLoader()); + assertThat("uses parent class loader", self, sameInstance((Object) getClass())); + + assertThat(created1.getClassLoader(), not(sameInstance(getClass().getClassLoader()))); + assertThat(created1.getClassLoader(), sameInstance(created2.getClassLoader())); + + JavassistConverter another = new JavassistConverter(getClass()); + CtClass example3 = another.getClassPool().makeClass("Example1"); + Class<?> created3 = another.toClass(example3); + assertThat(created3.getName(), is("Example1")); + assertThat(created3, is(not((Object) created1))); + } + + /** + * Test method for {@link JavassistConverter#loadCtClass(Class)}. + * @throws Exception if occur + */ + @Test + public void testLoadCtClass() throws Exception { + JavassistConverter converter = new JavassistConverter(getClass()); + CtClass example = converter.getClassPool().makeClass("Example"); + Class<?> exampleClass = converter.toClass(example); + + CtClass object = converter.loadCtClass(Object.class); + CtClass self = converter.loadCtClass(getClass()); + CtClass example2 = converter.loadCtClass(exampleClass); + + assertThat(object.getName(), is("java.lang.Object")); + assertThat(self.getName(), is(getClass().getName())); + assertThat(example2.getName(), is("Example")); + + try { + converter.loadCtClass(int.class); + fail("primitive type"); + } catch (IllegalArgumentException e) { + // ok. + } + try { + converter.loadCtClass(Object[].class); + fail("array type"); + } catch (IllegalArgumentException e) { + // ok. + } + try { + converter.loadCtClass(Map.Entry.class); + fail("member type"); + } catch (IllegalArgumentException e) { + // ok. + } + try { + class Local { + // no members + } + converter.loadCtClass(Local.class); + fail("local class"); + } catch (IllegalArgumentException e) { + // ok. + } + try { + converter.loadCtClass(new Object[] {}.getClass()); + fail("anonymous class"); + } catch (IllegalArgumentException e) { + // ok. + } + } + + /** + * Test method for {@link JavassistConverter#toClass(javassist.CtClass)}. + * @throws Exception if occur + */ + @Test + public void testToClass_Array() throws Exception { + JavassistConverter converter = new JavassistConverter(getClass()); + ClassPool pool = converter.getClassPool(); + + pool.makeClass("Example"); + CtClass a = pool.get("Example[]"); + CtClass aa = pool.get("Example[][]"); + + Class<?> array = converter.toClass(a); + Class<?> arrayarray = converter.toClass(aa); + + assertThat(array.isArray(), is(true)); + Class<?> component = array.getComponentType(); + assertThat(component.isArray(), is(false)); + assertThat(component.getName(), is("Example")); + + assertThat(arrayarray.isArray(), is(true)); + assertThat(arrayarray.getComponentType(), sameInstance((Object) array)); + } + + /** + * Test method for {@link JavassistConverter#toClass(javassist.CtClass)}. + * @throws Exception if occur + */ + @Test + public void testToClass_Class() throws Exception { + JavassistConverter converter = new JavassistConverter(getClass()); + ClassPool pool = converter.getClassPool(); + + CtClass example = pool.makeClass("Example"); + example.addInterface(pool.get("java.util.concurrent.Callable")); + + CtConstructor ctor = new CtConstructor(new CtClass[0], example); + ctor.setBody("super();"); + example.addConstructor(ctor); + + CtMethod call = new CtMethod(pool.get("java.lang.Object"), "call", new CtClass[0], example); + call.setBody("return \"TEST\";"); + example.addMethod(call); + + Class<?> klass = converter.toClass(example); + assertThat(example.isFrozen(), is(true)); + Object instance = klass.newInstance(); + assertThat(instance, instanceOf(Callable.class)); + Object result = ((Callable<?>) instance).call(); + assertThat(result, is((Object) "TEST")); + + Class<?> replay = converter.toClass(example); + assertThat(replay, sameInstance((Object) klass)); + } + + /** + * Test method for {@link JavassistConverter#toClass(javassist.CtClass)}. + * @throws Exception if occur + */ + @Test + public void testToClass_Primitive() throws Exception { + JavassistConverter converter = new JavassistConverter(getClass()); + assertThat(converter.toClass(CtClass.voidType), is((Object) void.class)); + assertThat(converter.toClass(CtClass.intType), is((Object) int.class)); + assertThat(converter.toClass(CtClass.longType), is((Object) long.class)); + assertThat(converter.toClass(CtClass.floatType), is((Object) float.class)); + assertThat(converter.toClass(CtClass.doubleType), is((Object) double.class)); + assertThat(converter.toClass(CtClass.byteType), is((Object) byte.class)); + assertThat(converter.toClass(CtClass.shortType), is((Object) short.class)); + assertThat(converter.toClass(CtClass.charType), is((Object) char.class)); + assertThat(converter.toClass(CtClass.booleanType), is((Object) boolean.class)); + } + + /** + * Test method for {@link JavassistConverter#toClass(javassist.CtClass)}. + * @throws Exception if occur + */ + @Test + public void testToClass_PrimitiveArray() throws Exception { + JavassistConverter converter = new JavassistConverter(getClass()); + CtClass aInt = converter.getClassPool().get("[I"); + CtClass aaBoolean = converter.getClassPool().get("[[Z"); + + assertThat(converter.toClass(aInt), is((Object) int[].class)); + assertThat(converter.toClass(aaBoolean), is((Object) boolean[][].class)); + } + + /** + * Test method for {@link JavassistConverter#toClasses(javassist.CtClass[])}. + * @throws Exception if occur + */ + @Test + public void testToClasses() throws Exception { + JavassistConverter converter = new JavassistConverter(getClass()); + ClassPool pool = converter.getClassPool(); + CtClass example = pool.makeClass("Example"); + CtClass[] classes = { + CtClass.voidType, + pool.get("java.lang.Object"), + example, + pool.get("[[I"), + }; + Class<?>[] results = converter.toClasses(classes); + assertThat(results.length, is(4)); + assertThat(results[0], is((Object) void.class)); + assertThat(results[1], is((Object) Object.class)); + assertThat(results[2].getName(), is("Example")); + assertThat(results[3], is((Object) int[][].class)); + assertThat(example.isFrozen(), is(true)); + } +} Property changes on: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/helper/JavassistConverterTest.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + Date Author Id Revision HeadURL Added: svn:eol-style + native