[Jiemamy-notify:2817] commit [3739] ブリッジメソッドに関して少しだけ実装を強化。

Zurück zum Archiv-Index

svnno****@sourc***** svnno****@sourc*****
2009年 10月 9日 (金) 23:08:04 JST


Revision: 3739
          http://sourceforge.jp/projects/jiemamy/svn/view?view=rev&revision=3739
Author:   ashigeru
Date:     2009-10-09 23:08:04 +0900 (Fri, 09 Oct 2009)

Log Message:
-----------
ブリッジメソッドに関して少しだけ実装を強化。
型変数を利用した仮引数に関しては未実装だが、共変戻り値型に関しては少しだけ対応した。

Modified Paths:
--------------
    leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/InterfaceEnhancer.java
    leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/EnhanceManipulator.java
    leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceEnhancerTest.java

Added Paths:
-----------
    leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/ExtendsListExplicit.java
    leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/ExtendsListImplicit.java
    leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceFactoryProductConflict.java
    leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceListFactory.java
    leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceProductCharSequence.java
    leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceProductString.java

Modified: leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/InterfaceEnhancer.java
===================================================================
--- leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/InterfaceEnhancer.java	2009-10-09 10:03:38 UTC (rev 3738)
+++ leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/InterfaceEnhancer.java	2009-10-09 14:08:04 UTC (rev 3739)
@@ -92,10 +92,9 @@
  *   </li>
  * </ul>
  * <p>
- * なお、{@code v0.2.0}の時点ではファクトリ、およびプロダクトのco-variant return typeなどに正しく対応できていない。
- * JDK5.0で対応されたブリッジメソッドが導入されるようなメソッドをファクトリおよびプロダクトに作成した場合の挙動は保証されない。
- * たとえば、メソッドオーバーライド時の戻り値型にサブタイプを指定したり、
- * 引数に型変数を直接指定するメソッドを持つインターフェースを継承する場合などには注意が必要である。
+ * なお、現在の実装ではパラメータ化されたインターフェースを利用したファクトリ、プロダクトの拡張に関する
+ * いくつかの不具合が存在する。
+ * このため、それらを親インターフェースにもつファクトリやプロダクトの使用時の挙動は保証されない。
  * </p>
  * @version 0.2.0
  * @since 0.2.0

Modified: leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/EnhanceManipulator.java
===================================================================
--- leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/EnhanceManipulator.java	2009-10-09 10:03:38 UTC (rev 3738)
+++ leto/factory-enhancer/trunk/src/main/java/org/jiemamy/utils/enhancer/helper/EnhanceManipulator.java	2009-10-09 14:08:04 UTC (rev 3739)
@@ -19,8 +19,11 @@
 import java.lang.reflect.Modifier;
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -55,6 +58,16 @@
 	
 	private static final Logger LOG = LoggerFactory.getLogger(EnhanceManipulator.class);
 	
+	/**
+	 * ブリッジメソッドに対する修飾子のフラグ。
+	 */
+	private static final int BRIDGE = 0x00000040;
+	
+	/**
+	 * コンパイラ合成要素に対する修飾子のフラグ。
+	 */
+	private static final int SYNTHETIC = 0x00001000;
+	
 	private static final Pattern AVOID_NAME_PATTERN = Pattern.compile("(java\\.|javax\\.|sun\\.).*"); //$NON-NLS-1$
 	
 	private static final String ENHANCE_CLASS = "__ENHANCED__";
@@ -169,29 +182,37 @@
 		LOG.debug("A factory implementation: {} implements {}",
 				implementation.getName(), factoryInterface.getName());
 		
-		// FIXME ブリッジメソッドを作成する
-		for (NameAndParameter identity : collectInterfaceMethods(factoryInterface)) {
-			implementFactoryMethod(implementation, identity.method, targetProducts);
+		// ファクトリインターフェースが提供するすべてのメソッドを実装
+		for (MethodGroup group : collectInterfaceMethods(factoryInterface)) {
+			implementFactoryMethod(implementation, group, targetProducts);
 		}
 		return implementation;
 	}
 	
 	private static void implementFactoryMethod(
 			CtClass implementation,
-			CtMethod factoryMethod,
+			MethodGroup factoryMethodGroup,
 			Map<CtClass, CtClass> targetProducts) throws EnhanceException {
 		assert implementation != null;
-		assert factoryMethod != null;
+		assert factoryMethodGroup != null;
 		assert targetProducts != null;
-		LOG.trace("Implementing a factory method: {}", factoryMethod);
+		LOG.trace("Implementing a factory method: {}", factoryMethodGroup);
 		
+		if (factoryMethodGroup.hasMostSpecificMethod() == false) {
+			throw new EnhanceException(MessageFormat.format(
+					"{0} has ambigous return type",
+					factoryMethodGroup),
+					null);
+		}
+		
+		CtMethod factoryMethod = factoryMethodGroup.getMostSpecificMethod();
 		CtClass productType;
 		try {
 			productType = factoryMethod.getReturnType();
 		} catch (NotFoundException e) {
 			throw new EnhanceException(MessageFormat.format(
 					"Cannot detect product interface for {0}",
-					factoryMethod),
+					factoryMethodGroup),
 					e);
 		}
 		CtClass productImpl = targetProducts.get(productType);
@@ -203,6 +224,7 @@
 		}
 		createProductConstructor(productImpl, factoryMethod);
 		createFactoryMethod(implementation, factoryMethod, productImpl);
+		createBridgeMethods(implementation, factoryMethodGroup);
 	}
 	
 	/**
@@ -276,6 +298,13 @@
 		}
 	}
 	
+	/**
+	 * ファクトリインターフェースで定義されたファクトリメソッドをファクトリクラス上に実装する。
+	 * @param factoryImplementation ファクトリクラス
+	 * @param factoryMethod インターフェースで定義されたファクトリメソッド
+	 * @param productImplementation ファクトリが生成するプロダクトの実装クラス
+	 * @throws EnhanceException ファクトリメソッドの実装に失敗した場合
+	 */
 	private static void createFactoryMethod(
 			CtClass factoryImplementation,
 			CtMethod factoryMethod,
@@ -320,6 +349,95 @@
 	}
 	
 	/**
+	 * 指定のクラス上に対象のメソッドグループが提供すべきブリッジメソッドを生成する。
+	 * @param aClass 対象のクラス
+	 * @param methodGroup 対象のメソッドグループ
+	 * @throws EnhanceException ブリッジメソッドの生成に失敗した場合
+	 */
+	private static void createBridgeMethods(
+			CtClass aClass,
+			MethodGroup methodGroup) throws EnhanceException {
+		assert aClass != null;
+		assert methodGroup != null;
+		assert methodGroup.hasMostSpecificMethod();
+		Collection<CtMethod> less = methodGroup.getLessSpecificMethods();
+		if (less.isEmpty()) {
+			return;
+		}
+		LOG.trace("Creating bridge methods: {}", methodGroup);
+		CtMethod most = methodGroup.getMostSpecificMethod();
+		CtClass ownerOfMost = most.getDeclaringClass();
+		for (CtMethod source : less) {
+			try {
+				// すでに本体が定義されたメソッドについては何もしない
+				if (isBodyDeclared(aClass, source)) {
+					continue;
+				}
+				CtMethod bridge = new CtMethod(source, aClass, null);
+				bridge.setModifiers(bridge.getModifiers() & ~(Modifier.ABSTRACT) | BRIDGE | SYNTHETIC);
+				// FIXME ちょっと怪しい。反例を探すこと
+				assert isStatic(most) == false;
+				assert bridge.getReturnType().equals(CtClass.voidType) == false;
+				bridge.setBody(String.format(
+						"return ((%s) this).%s($$);",
+						ownerOfMost.getName(),
+						bridge.getName()));
+				aClass.addMethod(bridge);
+			} catch (CannotCompileException e) {
+				throw new EnhanceException(MessageFormat.format(
+						"Cannot create bridge method {0}#{1}{2}",
+						aClass.getName(),
+						source.getName(),
+						source.getSignature()),
+						e);
+			} catch (NotFoundException e) {
+				throw new EnhanceException(MessageFormat.format(
+						"Cannot create bridge method {0}#{1}{2}",
+						aClass.getName(),
+						source.getName(),
+						source.getSignature()),
+						e);
+			}
+		}
+	}
+	
+	/**
+	 * 指定のクラスに指定のメソッドと同じシグネチャを有するメソッドが、本体ごと宣言されている場合のみ{@code true}を返す。
+	 * @param aClass 対象のクラス
+	 * @param method 対象のメソッド
+	 * @return 本体が宣言されていれば{@code true}
+	 */
+	private static boolean isBodyDeclared(CtClass aClass, CtMethod method) {
+		assert aClass != null;
+		assert method != null;
+		String name = method.getName();
+		String descriptor = method.getSignature();
+		try {
+			for (CtClass current = aClass; current != null; current = current.getSuperclass()) {
+				for (CtMethod declared : aClass.getDeclaredMethods()) {
+					if (declared.getName().equals(name) == false) {
+						continue;
+					}
+					if (declared.getSignature().equals(descriptor) == false) {
+						continue;
+					}
+					int modifiers = declared.getModifiers();
+					if (Modifier.isPrivate(modifiers)) {
+						return false;
+					}
+					if (Modifier.isAbstract(modifiers)) {
+						return false;
+					}
+					return true;
+				}
+			}
+			return false;
+		} catch (NotFoundException e) {
+			return false;
+		}
+	}
+	
+	/**
 	 * インターフェースプロダクトの実装クラスを生成して返す。
 	 * <p>
 	 * 生成されるクラスは、指定された基本クラスとインターフェースをそれぞれ親にもち。
@@ -369,6 +487,17 @@
 		// そう考えた場合、作成したクラス implementation はいくつかのメソッドを実装しない具象クラスとなってソースコード的には不正であるものの
 		// バイナリ的には問題なくリンクできる。
 		
+		// ただし、ブリッジメソッドは自分で作らないといけない模様...
+		for (MethodGroup group : collectInterfaceMethods(baseInterface)) {
+			if (group.hasMostSpecificMethod() == false) {
+				throw new EnhanceException(MessageFormat.format(
+						"{0} has ambigous return type",
+						group),
+						null);
+			}
+			createBridgeMethods(implementation, group);
+		}
+		
 		return implementation;
 	}
 	
@@ -384,10 +513,10 @@
 	 * @throws EnhanceException メソッドの計算に失敗した場合
 	 * @since 0.2.0
 	 */
-	private static Set<NameAndParameter> collectInterfaceMethods(CtClass anInterface) throws EnhanceException {
+	private static Set<MethodGroup> collectInterfaceMethods(CtClass anInterface) throws EnhanceException {
 		assert anInterface != null;
 		assert anInterface.isInterface();
-		Map<NameAndParameter, NameAndParameter> results = new HashMap<NameAndParameter, NameAndParameter>();
+		Map<NameAndParameter, MethodGroup> results = new HashMap<NameAndParameter, MethodGroup>();
 		
 		LinkedList<CtClass> work = new LinkedList<CtClass>();
 		work.addFirst(anInterface);
@@ -402,27 +531,14 @@
 				for (CtMethod method : targetInterface.getDeclaredMethods()) {
 					NameAndParameter target = new NameAndParameter(method);
 					
-					// オーバーライド性のあるものが既に追加されているか
-					NameAndParameter override = results.get(target);
-					if (override == null) {
-						// オーバーライドしていなければそのまま追加
-						results.put(target, target);
-					} else if (target.method.getSignature().equals(override.method.getSignature())) {
-						// まずはシグネチャの一致で高速に判定する
-						// シグネチャが一致すれば co-variant return type によるオーバーライド戻り値の変更をやってない
-						// そのため、多重定義は不要
+					// 名前とパラメータが一致するメソッドがすでに追加されているか
+					MethodGroup group = results.get(target);
+					if (group == null) {
+						// 追加されていなければ、新しいグループを作成
+						results.put(target, new MethodGroup(method));
 					} else {
-						// FIXME 今のところ、co-variant return typeには未対応
-						throw new EnhanceException(
-								MessageFormat.format(
-								"Co-variant return type is not supported, ({0}#{1}{2} <-> {3}#{4}{5})",
-								override.method.getDeclaringClass().getName(),
-								override.method.getName(),
-								override.method.getSignature(),
-								target.method.getDeclaringClass().getName(),
-								target.method.getName(),
-								target.method.getSignature()),
-								null);
+						// 追加されていれば、そのグループにメソッドの追加を試みる
+						group.add(method);
 					}
 				}
 				for (CtClass superInterface : targetInterface.getInterfaces()) {
@@ -437,7 +553,7 @@
 			}
 		}
 		
-		return new HashSet<NameAndParameter>(results.values());
+		return new HashSet<MethodGroup>(results.values());
 	}
 	
 	/**
@@ -888,6 +1004,7 @@
 		List<Aspect<CtMethod>> results = new ArrayList<Aspect<CtMethod>>();
 		CtField holder = null;
 		int enhanceIndex = 0;
+		// FIXME override check
 		for (CtMethod method : base.getMethods()) {
 			if (enhanceManager.isLegalJoinpoint(method) == false) {
 				continue;
@@ -1054,14 +1171,159 @@
 	
 
 	/**
+	 * 同じ名前と仮引数型のリストを持つメソッドのグループ。
+	 * @version $Id$
+	 * @author Suguru ARAKAWA
+	 */
+	private static class MethodGroup {
+		
+		private final Map<CtClass, CtMethod> returnTypeAndMethods;
+		
+		private final Set<CtClass> maximallySpecificTypes;
+		
+		final String name;
+		
+		final String parameters;
+		
+
+		/**
+		 * インスタンスを生成する。
+		 * @param method グループの最初のメンバとなるメソッド
+		 * @throws NotFoundException 型の解決に失敗した場合
+		 */
+		public MethodGroup(CtMethod method) throws NotFoundException {
+			assert method != null;
+			returnTypeAndMethods = new HashMap<CtClass, CtMethod>();
+			maximallySpecificTypes = new HashSet<CtClass>();
+			name = method.getName();
+			parameters = Descriptor.getParamDescriptor(method.getSignature());
+			CtClass returnType = method.getReturnType();
+			returnTypeAndMethods.put(returnType, method);
+			maximallySpecificTypes.add(returnType);
+		}
+		
+		/**
+		 * 指定のメソッドをこのグループに追加する。
+		 * <p>
+		 * すでに同じシグネチャを持つメソッドがグループに存在する場合、この呼び出しは何も行わない。
+		 * </p>
+		 * @param method 追加するメソッド
+		 * @return このグループに追加したら{@code true}、すでに同じシグネチャを持つものがいれば{@code false}
+		 * @throws NotFoundException 型の解決に失敗した場合
+		 */
+		public boolean add(CtMethod method) throws NotFoundException {
+			assert method != null;
+			assert name.equals(method.getName());
+			assert parameters.equals(Descriptor.getParamDescriptor(method.getSignature()));
+			CtClass type = method.getReturnType();
+			// already exists
+			if (returnTypeAndMethods.containsKey(type)) {
+				return false;
+			}
+			
+			returnTypeAndMethods.put(type, method);
+			updateMaximallySpecific(type);
+			return true;
+		}
+		
+		/**
+		 * 最も限定的なメソッドがこのグループに存在する場合のみ{@code true}を返す。
+		 * <p>
+		 * 最大<em>限</em>に限定的なメソッドが複数存在する場合、このメソッドは{@code false}を返す。
+		 * </p>
+		 * @return 最大に限定的なメソッドがこのグループに存在する場合のみ{@code true}
+		 */
+		public boolean hasMostSpecificMethod() {
+			return maximallySpecificTypes.size() == 1;
+		}
+		
+		/**
+		 * このグループの最も限定的な限定的なメソッドを返す。
+		 * @return このグループの最も限定的な限定的なメソッド
+		 * @throws IllegalStateException 最も限定的なメソッドを一意に特定できない場合
+		 * @see #hasMostSpecificMethod()
+		 */
+		public CtMethod getMostSpecificMethod() {
+			if (hasMostSpecificMethod() == false) {
+				throw new IllegalStateException();
+			}
+			assert maximallySpecificTypes.size() == 1;
+			CtClass returnType = maximallySpecificTypes.iterator().next();
+			CtMethod theMost = returnTypeAndMethods.get(returnType);
+			assert theMost != null;
+			return theMost;
+		}
+		
+		/**
+		 * このグループの最も限定的な限定的なメソッドを除く、すべてのメソッド返す。
+		 * @return このグループの最も限定的な限定的なメソッドを除く、すべてのメソッド
+		 * @throws IllegalStateException 最も限定的なメソッドを一意に特定できない場合
+		 * @see #hasMostSpecificMethod()
+		 */
+		public Collection<CtMethod> getLessSpecificMethods() {
+			if (hasMostSpecificMethod() == false) {
+				throw new IllegalStateException();
+			}
+			assert maximallySpecificTypes.size() == 1;
+			if (returnTypeAndMethods.size() == 1) {
+				assert returnTypeAndMethods.keySet().equals(maximallySpecificTypes);
+				return Collections.emptySet();
+			}
+			Collection<CtMethod> results = new HashSet<CtMethod>();
+			for (Map.Entry<CtClass, CtMethod> entry : returnTypeAndMethods.entrySet()) {
+				if (maximallySpecificTypes.contains(entry.getKey())) {
+					continue;
+				}
+				results.add(entry.getValue());
+			}
+			return results;
+		}
+		
+		/**
+		 * 戻り値型が最大限に限定的なものを探すため、現時点で最大限に限定的な型のうち、
+		 * 指定の型のほうが限定的であるものを探して全体から除去する。
+		 * <p>
+		 * 現時点で最大限に限定的な型のいずれかよりも指定の型が限定的である場合、
+		 * 最大限に限定的な型の集合に、指定の型を追加する。
+		 * </p>
+		 * @param type 対象の型
+		 * @throws NotFoundException 型の解決に失敗した場合
+		 */
+		private void updateMaximallySpecific(CtClass type) throws NotFoundException {
+			assert type != null;
+			assert maximallySpecificTypes.isEmpty() == false;
+			if (maximallySpecificTypes.contains(type)) {
+				return;
+			}
+			boolean specific = false;
+			for (Iterator<CtClass> iter = maximallySpecificTypes.iterator(); iter.hasNext();) {
+				CtClass currentSpecific = iter.next();
+				assert type.equals(currentSpecific) == false;
+				if (type.subtypeOf(currentSpecific)) {
+					iter.remove();
+					specific = true;
+				}
+			}
+			if (specific) {
+				maximallySpecificTypes.add(type);
+			}
+		}
+		
+		@Override
+		public String toString() {
+			return MessageFormat.format(
+					"{0}{1}:{2}",
+					name, parameters, returnTypeAndMethods.keySet());
+		}
+	}
+	
+	/**
 	 * 名前とデスクリプタのペア。主にオーバーロード判定に利用する。
 	 * @version $Id$
 	 * @author Suguru ARAKAWA
 	 */
 	private static class NameAndParameter {
 		
-		final CtMethod method;
-		
 		final String name;
 		
 		final String parameter;
@@ -1076,7 +1338,6 @@
 			name = method.getName();
 			String paramAndReturn = method.getSignature();
 			parameter = Descriptor.getParamDescriptor(paramAndReturn);
-			this.method = method;
 		}
 		
 		@Override

Added: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/ExtendsListExplicit.java
===================================================================
--- leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/ExtendsListExplicit.java	                        (rev 0)
+++ leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/ExtendsListExplicit.java	2009-10-09 14:08:04 UTC (rev 3739)
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2007-2009 Jiemamy Project and the Others.
+ * Created on 2009/10/04
+ *
+ * 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;
+
+import java.util.List;
+
+/**
+ * {@link List}を型引数付きで継承し、明示的にメソッドをオーバーライドしたもの。
+ * @version $Id$
+ * @author Suguru ARAKAWA
+ */
+public interface ExtendsListExplicit extends List<String> {
+	
+	boolean add(String o);
+}


Property changes on: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/ExtendsListExplicit.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Author Id Revision HeadURL
Added: svn:eol-style
   + native

Added: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/ExtendsListImplicit.java
===================================================================
--- leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/ExtendsListImplicit.java	                        (rev 0)
+++ leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/ExtendsListImplicit.java	2009-10-09 14:08:04 UTC (rev 3739)
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2007-2009 Jiemamy Project and the Others.
+ * Created on 2009/10/04
+ *
+ * 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;
+
+import java.util.List;
+
+/**
+ * {@link List}を型引数付きで継承し、明示的にメソッドをオーバーライドしないもの。
+ * @version $Id$
+ * @author Suguru ARAKAWA
+ */
+public interface ExtendsListImplicit extends List<String> {
+	
+}


Property changes on: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/ExtendsListImplicit.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Author Id Revision HeadURL
Added: svn:eol-style
   + native

Modified: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceEnhancerTest.java
===================================================================
--- leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceEnhancerTest.java	2009-10-09 10:03:38 UTC (rev 3738)
+++ leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceEnhancerTest.java	2009-10-09 14:08:04 UTC (rev 3739)
@@ -25,6 +25,7 @@
 
 import java.lang.reflect.InvocationTargetException;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
@@ -35,6 +36,7 @@
 import org.junit.Ignore;
 import org.junit.Test;
 
+import org.jiemamy.utils.enhancer.aspect.StringParameterPointcut;
 import org.jiemamy.utils.enhancer.aspect.StringResultPointcut;
 import org.jiemamy.utils.enhancer.aspect.ThroughHandler;
 
@@ -254,10 +256,8 @@
 	
 	/**
 	 * Test method for {@link org.jiemamy.utils.enhancer.AbstractEnhancer#getFactory()}.
-	 * FIXME implement co-variant return type
 	 * @throws Exception if occur
 	 */
-	@Ignore
 	@Test
 	public void testGetFactory_OverrideWithReturnSubType() throws Exception {
 		Enhance enhance = new Enhance(new StringResultPointcut(), new InvocationHandler() {
@@ -290,10 +290,8 @@
 	
 	/**
 	 * Test method for {@link org.jiemamy.utils.enhancer.AbstractEnhancer#getFactory()}.
-	 * FIXME implement co-variant return type
 	 * @throws Exception if occur
 	 */
-	@Ignore
 	@Test
 	public void testGetFactory_OverrideConflictReturnSubType() throws Exception {
 		Enhance enhance = new Enhance(new StringResultPointcut(), new InvocationHandler() {
@@ -325,6 +323,92 @@
 	}
 	
 	/**
+	 * Test method for {@link org.jiemamy.utils.enhancer.AbstractEnhancer#getFactory()}.
+	 * @throws Exception if occur
+	 */
+	@Test
+	public void testGetFactory_ProductConflictReturnSubType() throws Exception {
+		Enhance enhance = new Enhance(new StringResultPointcut(), new InvocationHandler() {
+			
+			public Object handle(Invocation invocation) {
+				return "Hello";
+			}
+		});
+		InterfaceEnhancer<InterfaceFactoryProductConflict> enhancer =
+				new InterfaceEnhancer<InterfaceFactoryProductConflict>(
+				InterfaceFactoryProductConflict.class,
+				Object.class,
+				enhances(enhance));
+		Factory<? extends InterfaceFactoryProductConflict> metaFactory = enhancer.getFactory();
+		InterfaceFactoryProductConflict factory = metaFactory.newInstance();
+		
+		InterfaceProductString productString = factory.newProduct();
+		InterfaceProductCharSequence productCharSequence = productString;
+		assertThat(productString.getMessage(), is("Hello"));
+		assertThat(productCharSequence.getMessage(), is((CharSequence) "Hello"));
+	}
+	
+	/**
+	 * Test method for {@link org.jiemamy.utils.enhancer.AbstractEnhancer#getFactory()}.
+	 * TODO 仮引数型に型引数を直接とる(パラメータ化型ではなく、型変数をそのまま使う)インターフェースを継承し、
+	 * そのメソッドをオーバーライドしなかった場合にブリッジメソッドを作るかどうか。
+	 * @throws Exception if occur
+	 */
+	@Ignore
+	@Test
+	public void testGetFactory_ProductTypeVariableReificationImplicit() throws Exception {
+		Enhance enhance = new Enhance(new StringParameterPointcut(), new InvocationHandler() {
+			
+			public Object handle(Invocation invocation) {
+				return false;
+			}
+		});
+		InterfaceEnhancer<InterfaceListFactory> enhancer =
+				new InterfaceEnhancer<InterfaceListFactory>(
+				InterfaceListFactory.class,
+				Object.class,
+				enhances(enhance));
+		Factory<? extends InterfaceListFactory> metaFactory = enhancer.getFactory();
+		InterfaceListFactory factory = metaFactory.newInstance();
+		
+		ExtendsListImplicit product = factory.newImplicit();
+		assertThat(product.add("Hello"), is(false));
+		
+		List<String> list = factory.newImplicit();
+		assertThat(list.add("Hello"), is(false));
+	}
+	
+	/**
+	 * Test method for {@link org.jiemamy.utils.enhancer.AbstractEnhancer#getFactory()}.
+	 * TODO 仮引数型に型引数を直接とる(パラメータ化型ではなく、型変数をそのまま使う)インターフェースを継承し、
+	 * そのメソッドをオーバーライドした場合にブリッジメソッドを作る。
+	 * @throws Exception if occur
+	 */
+	@Ignore
+	@Test
+	public void testGetFactory_ProductTypeVariableReificationExplicit() throws Exception {
+		Enhance enhance = new Enhance(new StringParameterPointcut(), new InvocationHandler() {
+			
+			public Object handle(Invocation invocation) {
+				return true;
+			}
+		});
+		InterfaceEnhancer<InterfaceListFactory> enhancer =
+				new InterfaceEnhancer<InterfaceListFactory>(
+				InterfaceListFactory.class,
+				Object.class,
+				enhances(enhance));
+		Factory<? extends InterfaceListFactory> metaFactory = enhancer.getFactory();
+		InterfaceListFactory factory = metaFactory.newInstance();
+		
+		ExtendsListExplicit product = factory.newExplicit();
+		assertThat(product.add("Hello"), is(true));
+		
+		List<String> list = product;
+		assertThat(list.add("Hello"), is(true));
+	}
+	
+	/**
 	 * Test method for {@link InterfaceEnhancer#InterfaceEnhancer(java.lang.Class, java.lang.Class, java.util.List)}.
 	 */
 	@Test(expected = IllegalArgumentException.class)

Added: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceFactoryProductConflict.java
===================================================================
--- leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceFactoryProductConflict.java	                        (rev 0)
+++ leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceFactoryProductConflict.java	2009-10-09 14:08:04 UTC (rev 3739)
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2007-2009 Jiemamy Project and the Others.
+ * Created on 2009/10/04
+ *
+ * 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;
+
+/**
+ * {@link InterfaceProductString}を生成するファクトリ。
+ * @version $Id$
+ * @author Suguru ARAKAWA
+ */
+public interface InterfaceFactoryProductConflict {
+	
+	/**
+	 * @return {@link InterfaceProductString}
+	 */
+	InterfaceProductString newProduct();
+}


Property changes on: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceFactoryProductConflict.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Author Id Revision HeadURL
Added: svn:eol-style
   + native

Added: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceListFactory.java
===================================================================
--- leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceListFactory.java	                        (rev 0)
+++ leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceListFactory.java	2009-10-09 14:08:04 UTC (rev 3739)
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2007-2009 Jiemamy Project and the Others.
+ * Created on 2009/10/04
+ *
+ * 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;
+
+/**
+ * {@link ExtendsListImplicit},
+ * {@link ExtendsListExplicit}を生成するファクトリ。
+ * @version $Id$
+ * @author Suguru ARAKAWA
+ */
+public interface InterfaceListFactory {
+	
+	/**
+	 * @return {@link ExtendsListImplicit}
+	 */
+	ExtendsListImplicit newImplicit();
+	
+	/**
+	 * @return {@link ExtendsListExplicit}
+	 */
+	ExtendsListExplicit newExplicit();
+}


Property changes on: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceListFactory.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Author Id Revision HeadURL
Added: svn:eol-style
   + native

Added: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceProductCharSequence.java
===================================================================
--- leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceProductCharSequence.java	                        (rev 0)
+++ leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceProductCharSequence.java	2009-10-09 14:08:04 UTC (rev 3739)
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2007-2009 Jiemamy Project and the Others.
+ * Created on 2009/10/04
+ *
+ * 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;
+
+/**
+ * 単純なプロダクト。
+ * @version $Id$
+ * @author Suguru ARAKAWA
+ */
+public interface InterfaceProductCharSequence {
+	
+	/**
+	 * @return nothing
+	 */
+	CharSequence getMessage();
+}


Property changes on: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceProductCharSequence.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Author Id Revision HeadURL
Added: svn:eol-style
   + native

Added: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceProductString.java
===================================================================
--- leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceProductString.java	                        (rev 0)
+++ leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceProductString.java	2009-10-09 14:08:04 UTC (rev 3739)
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2007-2009 Jiemamy Project and the Others.
+ * Created on 2009/10/04
+ *
+ * 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;
+
+/**
+ * 共変戻り値型を利用するプロダクトインターフェース。
+ * @version $Id$
+ * @author Suguru ARAKAWA
+ */
+public interface InterfaceProductString extends InterfaceProductCharSequence {
+	
+	/**
+	 * @return nothing
+	 */
+	String getMessage();
+}


Property changes on: leto/factory-enhancer/trunk/src/test/java/org/jiemamy/utils/enhancer/InterfaceProductString.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Author Id Revision HeadURL
Added: svn:eol-style
   + native




Jiemamy-notify メーリングリストの案内
Zurück zum Archiv-Index