svnno****@sourc*****
svnno****@sourc*****
2008年 11月 19日 (水) 01:51:41 JST
Revision: 2170 http://svn.sourceforge.jp/view?root=jiemamy&view=rev&rev=2170 Author: shin1 Date: 2008-11-19 01:51:41 +0900 (Wed, 19 Nov 2008) Log Message: ----------- [CORE-80]ChangeSupportの自動修正もバブリング対応した。 Modified Paths: -------------- sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/CollectionProperty.java sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/JiemamyModelDoclet.java sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeSupportImpl.vm -------------- next part -------------- Modified: sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/CollectionProperty.java =================================================================== --- sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/CollectionProperty.java 2008-11-18 16:40:43 UTC (rev 2169) +++ sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/CollectionProperty.java 2008-11-18 16:51:41 UTC (rev 2170) @@ -9,6 +9,7 @@ import org.jiemamy.event.collectionimpl.ObservableSet; public class CollectionProperty { + private String getterName; private String name; private String nameUpper; private String nameSingle; @@ -181,4 +182,12 @@ public void setMap(boolean isMap) { this.isMap = isMap; } + + public String getGetterName() { + return getterName; + } + + public void setGetterName(String getterName) { + this.getterName = getterName; + } } Modified: sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/JiemamyModelDoclet.java =================================================================== --- sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/JiemamyModelDoclet.java 2008-11-18 16:40:43 UTC (rev 2169) +++ sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/java/org/jiemamy/core/eventcodegen/JiemamyModelDoclet.java 2008-11-18 16:51:41 UTC (rev 2170) @@ -2,7 +2,6 @@ import java.io.File; import java.io.FileWriter; -import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -16,16 +15,17 @@ import org.apache.velocity.app.Velocity; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; +import org.jiemamy.core.model.AbstractModel; import org.jiemamy.spec.model.JiemamyModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import com.sun.javadoc.AnnotationDesc; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.Doclet; import com.sun.javadoc.FieldDoc; import com.sun.javadoc.LanguageVersion; import com.sun.javadoc.RootDoc; import com.sun.javadoc.Type; -import com.sun.javadoc.AnnotationDesc.ElementValuePair; /** * Event用のソースを自動生成する。 j-coreプロジェクト配下のソースを読み込み、 {@link JiemamyModel}を発見した場合にその{@link JiemamyModel}用のChangeListenerとChangeSupportを自動生成する。 @@ -43,9 +43,9 @@ * Imports」と「Source-Format」を行ってからCommitする事。 * <ul> * <li>../org.jiemamy.event/src/main/java/org/event/model配下の全てのフォルダ</li> - * <li>../org.jiemamy.spec.event/src/main/java/org/event/model配下の全てのフォルダ</li> * </ul> * </li> + * <li>また、RootModelだけgetterの名称にModifiableを付加する必要がある。</li> * </ul> * * @author shin1ogawa @@ -54,7 +54,7 @@ public List<JiemamyModel> model; public Map<Class<?>, CollectionProperty> collectionProperties = new HashMap<Class<?>, CollectionProperty>(); public static final String OUTPUTDIR_IMPLEMENTS = "../org.jiemamy.event/src/main/java/"; - public static final String OUTPUTDIR_SPECS = "../org.jiemamy.spec.event/src/main/java/"; + static Logger logger = LoggerFactory.getLogger(JiemamyModelDoclet.class); public static LanguageVersion languageVersion() { return LanguageVersion.JAVA_1_5; @@ -98,19 +98,24 @@ * 読み込んだ{@link ClassDoc}を処理する。 * * @param classDoc + * @throws Exception + * @throws ParseErrorException + * @throws ResourceNotFoundException */ - public static void processClassDoc(ClassDoc classDoc) { - try { + public static void processClassDoc(ClassDoc classDoc) + throws ResourceNotFoundException, ParseErrorException, Exception { + + if (!classDoc.isAbstract() && !classDoc.isEnum() + && !classDoc.simpleTypeName().startsWith("Abstract") + && !classDoc.simpleTypeName().endsWith("Adapter")) { try { - Class<?> clazz = Class.forName(classDoc.qualifiedName()); - // JiemamyModelのサブクラスでないものはClassCastExceptionを発生させて弾く。 - clazz.asSubclass(JiemamyModel.class); - processModel(classDoc); + Class<?> clazz = Class.forName(classDoc.qualifiedTypeName()); + if (AbstractModel.class.isAssignableFrom(clazz)) { + processModelAccessor(classDoc); + } } catch (Exception ex) { - // 無視する。 + return; } - } catch (Exception ex) { - // } } @@ -126,178 +131,116 @@ * @throws ParseErrorException * @throws ResourceNotFoundException */ - private static void processModel(ClassDoc classDoc) + private static void processModelAccessor(ClassDoc classDoc) throws ResourceNotFoundException, ParseErrorException, Exception { - System.out.println(classDoc.qualifiedTypeName() + ":" - + getPackageName(classDoc)); + // Importが必要なClass List<String> importClasses = new ArrayList<String>(); - addImportClasses(importClasses, classDoc.qualifiedTypeName()); - addImportClasses(importClasses, - "org.jiemamy.spec.event.ModelChangeListener"); - addImportClasses(importClasses, - "org.jiemamy.spec.event.ObservableCollectionChangeEvent"); + importClasses.add("org.jiemamy.event.AbstractModelChangeSupport"); + importClasses.add("org.jiemamy.spec.event.ModelChangeEvent"); + importClasses.add("org.jiemamy.spec.event.ModelChangeListener"); + importClasses.add("org.jiemamy.spec.event.ModelChangeSupport"); + importClasses.add("org.jiemamy.spec.event.Observable"); + // 属性の情報を保持するCollectionPropertyのList List<CollectionProperty> properties = new ArrayList<CollectionProperty>(); - FieldDoc[] fields = classDoc.fields(); - for (FieldDoc fieldDoc : fields) { - // Bindingアノテーションで修飾されているかを調査する。 - boolean hasBindingAnnotation = false; - AnnotationDesc[] annotations = fieldDoc.annotations(); - for (AnnotationDesc annotation : annotations) { - String annotationType = annotation.annotationType() - .qualifiedName(); - if (annotationType - .equals("org.seasar.framework.container.annotation.tiger.Binding")) { - ElementValuePair[] elementValues = annotation - .elementValues(); - for (ElementValuePair elementValue : elementValues) { - String valueString = elementValue.value().toString() - .replaceAll("\"", ""); - String elementString = elementValue.element() - .toString(); - if (elementString - .equals("org.seasar.framework.container.annotation.tiger.Binding.value()") - && (valueString.equals("set") - || valueString.equals("list") || valueString - .equals("map"))) { - // Bindingアノテーションのその引数が"list" "map" - // "set"のいずれかであるものが対象。 - hasBindingAnnotation = true; - break; - } - } - } - } - if (hasBindingAnnotation == false) { + for (FieldDoc fieldDoc : classDoc.fields()) { + Type returnType = fieldDoc.type(); + String returnTypeName = returnType.qualifiedTypeName(); + String fieldName = fieldDoc.name(); + String getterName = fieldDoc.name(); + getterName = "get" + getterName.substring(0, 1).toUpperCase() + + getterName.substring(1); + // インスタンス化してみる。 + Class<?> fieldType; + try { + fieldType = Class.forName(returnTypeName); + } catch (Exception ex) { + // インスタンス化できない。 continue; } - - Type type = fieldDoc.type(); - String fieldTypeName = type.qualifiedTypeName(); - Class<?> fieldType = Class.forName(fieldTypeName); - if (isSubClass(fieldType, List.class) - || isSubClass(fieldType, List.class)) { + if (List.class.isAssignableFrom(fieldType) + || Set.class.isAssignableFrom(fieldType)) { // ListまたはSetのサブクラス - String parameterClassName = getParameterClassName(fieldDoc); - addImportClasses(importClasses, fieldTypeName); + String parameterClassName = getParameterClassName(returnType); + addImportClasses(importClasses, returnTypeName); addImportClasses(importClasses, parameterClassName); - properties.add(new CollectionProperty(fieldDoc.name(), type - .qualifiedTypeName().toString(), parameterClassName)); - } else if (isSubClass(fieldType, Map.class)) { + CollectionProperty collectionProperty = new CollectionProperty( + fieldName, returnType.qualifiedTypeName().toString(), + parameterClassName); + properties.add(collectionProperty); + collectionProperty.setGetterName(getterName); + } else if (Map.class.isAssignableFrom(fieldType)) { // Mapのサブクラス - String[] parameterClassNames = getParameterClassNames(fieldDoc); - addImportClasses(importClasses, fieldTypeName); + String[] parameterClassNames = getParameterClassNames(returnType); + addImportClasses(importClasses, returnTypeName); addImportClasses(importClasses, parameterClassNames[0]); addImportClasses(importClasses, parameterClassNames[1]); - try { - CollectionProperty collectionProperty = new CollectionProperty( - fieldDoc.name(), type.qualifiedTypeName() - .toString(), parameterClassNames[1]); - collectionProperty - .setMapKeyClassName(parameterClassNames[0]); - properties.add(collectionProperty); - } catch (Exception ex) { - ex.printStackTrace(); - } + CollectionProperty collectionProperty = new CollectionProperty( + fieldName, returnType.qualifiedTypeName().toString(), + parameterClassNames[1]); + collectionProperty.setMapKeyClassName(parameterClassNames[0]); + properties.add(collectionProperty); + collectionProperty.setGetterName(getterName); } } Collections.sort(importClasses); // Templateからjavaファイルを生成する。 try { String packageName = getPackageName(classDoc).replaceAll( - "org.jiemamy.core", "org.jiemamy.spec.event"); - File dirForSpec = new File(OUTPUTDIR_SPECS + "org.jiemamy.core.model", "org.jiemamy.event.model"); + File dir = new File(OUTPUTDIR_IMPLEMENTS + packageName.replaceAll("\\.", "/")); - if (!dirForSpec.exists()) { - dirForSpec.mkdirs(); + if (!dir.exists()) { + dir.mkdirs(); } - // 実装のパッケージ名には"spec"を含まない。 - File dirForImpl = new File(OUTPUTDIR_IMPLEMENTS - + packageName.replaceAll("\\.spec", "").replaceAll("\\.", - "/")); - if (!dirForImpl.exists()) { - dirForImpl.mkdirs(); - } - VelocityContext velocityContext = new VelocityContext(); - velocityContext.put("package", packageName); - velocityContext.put("importClasses", importClasses); + String modelClassName = classDoc.name().toString().replace("Impl", ""); - velocityContext.put("modelClassName", modelClassName); - velocityContext.put("modelClassNameLower", classDoc.name() - .toString().substring(0, 1).toLowerCase() - + classDoc.name().toString().substring(1)); - velocityContext.put("properties", properties); - - // ChangeListenerの生成 - Template listenerTemplate = Velocity - .getTemplate("ChangeListener.vm"); - File file = new File(dirForSpec.getAbsolutePath() + "/" - + modelClassName + "ChangeListener.java"); - System.out.println(file.getAbsolutePath()); - Writer writer = new FileWriter(file); - listenerTemplate.merge(velocityContext, writer); - writer.flush(); - writer.close(); - - // ChangeSupportの生成 - addImportClasses(importClasses, "java.util.List"); - addImportClasses(importClasses, "java.util.ArrayList"); - addImportClasses(importClasses, - "org.jiemamy.spec.event.ModelChangeEvent"); + importClasses.add(getPackageName(classDoc).replaceAll( + "org.jiemamy.core.model", "org.jiemamy.spec.model") + + "." + modelClassName); // Model Interface if (properties.size() > 0) { + importClasses.add("java.lang.ref.WeakReference"); + importClasses.add("org.slf4j.Logger"); + importClasses.add("org.slf4j.LoggerFactory"); importClasses .add("org.jiemamy.spec.event.ObservableCollectionChangeListener"); + importClasses.add("org.seasar.framework.beans.BeanDesc"); + importClasses + .add("org.seasar.framework.beans.impl.BeanDescImpl"); + importClasses + .add("org.jiemamy.spec.event.ObservableCollectionChangeEvent"); + importClasses + .add("org.jiemamy.spec.event.ObservableCollectionChangeEvent.Timing"); + importClasses.add(classDoc.qualifiedName()); // Model + // Implementation + importClasses.add(getPackageName(classDoc).replaceAll( + "org.jiemamy.core.model", "org.jiemamy.spec.accessor") + + "." + modelClassName + "Accessor"); // Model + // Implementation } for (CollectionProperty property : properties) { addImportClasses(importClasses, property .getObservableCollectionClassName()); } - Collections.sort(importClasses); - Template supportTemplate = Velocity.getTemplate("ChangeSupport.vm"); - file = new File(dirForSpec.getAbsolutePath() + "/" + modelClassName - + "ChangeSupport.java"); - System.out.println(file.getAbsolutePath()); - writer = new FileWriter(file); - supportTemplate.merge(velocityContext, writer); - writer.flush(); - writer.close(); + VelocityContext velocityContext = new VelocityContext(); + velocityContext.put("package", packageName); + velocityContext.put("importClasses", importClasses); + velocityContext.put("modelClassName", modelClassName); + velocityContext.put("modelClassNameLower", classDoc.name() + .toString().substring(0, 1).toLowerCase() + + classDoc.name().toString().substring(1)); + velocityContext.put("properties", properties); // ChangeSupportImplの生成 velocityContext.put("package", packageName .replaceAll("\\.spec", "")); - addImportClasses(importClasses, "java.util.List"); - addImportClasses(importClasses, "java.util.ArrayList"); - addImportClasses(importClasses, "org.jiemamy.spec.event.Observable"); - addImportClasses(importClasses, packageName.replace(".event", "") - + "." + modelClassName.replace("Impl", "")); - addImportClasses(importClasses, - "org.jiemamy.spec.event.ModelChangeEvent"); - addImportClasses(importClasses, - "org.jiemamy.event.AbstractModelChangeSupport"); - addImportClasses(importClasses, - "org.jiemamy.spec.event.ModelChangeSupport"); - addImportClasses(importClasses, - "org.seasar.framework.beans.BeanDesc"); - addImportClasses(importClasses, - "org.seasar.framework.beans.impl.BeanDescImpl"); - addImportClasses(importClasses, - "org.jiemamy.spec.event.ObservableCollectionChangeEvent.Timing"); - if (properties.size() > 0) { - importClasses - .add("org.jiemamy.spec.event.ObservableCollectionChangeListener"); - } - for (CollectionProperty property : properties) { - addImportClasses(importClasses, property - .getObservableCollectionClassName()); - } Collections.sort(importClasses); - Template supportImplTemplate = Velocity - .getTemplate("ChangeSupportImpl.vm"); - file = new File(dirForImpl.getAbsolutePath() + "/" + modelClassName + Template template = Velocity.getTemplate("ChangeSupportImpl.vm"); + File file = new File(dir.getAbsolutePath() + "/" + modelClassName + "ChangeSupportImpl.java"); - System.out.println(file.getAbsolutePath()); - writer = new FileWriter(file); - supportImplTemplate.merge(velocityContext, writer); + logger.info(file.getAbsolutePath()); + FileWriter writer = new FileWriter(file); + template.merge(velocityContext, writer); writer.flush(); writer.close(); } catch (Exception ex) { @@ -305,21 +248,23 @@ } } - /** - * あるクラスがあるクラスのサブクラスかどうか。 - * - * @param subClass - * @param superClass - * @return - */ - private static boolean isSubClass(Class<?> subClass, Class<?> superClass) { - try { - subClass.asSubclass(superClass); - return true; - } catch (Exception ex) { - return false; - } - } + // + // /** + // * あるクラスがあるクラスのサブクラスかどうか。 + // * + // * @param subClass + // * @param superClass + // * @return + // */ + // private static boolean isSubClass(Class<?> subClass, Class<?> superClass) + // { + // try { + // subClass.asSubclass(superClass); + // return true; + // } catch (Exception ex) { + // return false; + // } + // } /** * パッケージ名を取得する。 @@ -338,9 +283,8 @@ * @param fieldDoc * @return */ - private static String getParameterClassName(FieldDoc fieldDoc) { - String parameterizedType = fieldDoc.type().asParameterizedType() - .toString(); + private static String getParameterClassName(Type type) { + String parameterizedType = type.asParameterizedType().toString(); int index1 = parameterizedType.indexOf('<'); int index2 = parameterizedType.lastIndexOf('>'); return parameterizedType.substring(index1 + 1, index2); @@ -352,9 +296,8 @@ * @param fieldDoc * @return */ - private static String[] getParameterClassNames(FieldDoc fieldDoc) { - String parameterizedType = fieldDoc.type().asParameterizedType() - .toString(); + private static String[] getParameterClassNames(Type type) { + String parameterizedType = type.asParameterizedType().toString(); int index1 = parameterizedType.indexOf('<'); int index2 = parameterizedType.lastIndexOf('>'); return parameterizedType.substring(index1 + 1, index2).split(","); Modified: sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeSupportImpl.vm =================================================================== --- sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeSupportImpl.vm 2008-11-18 16:40:43 UTC (rev 2169) +++ sandbox/org.jiemamy.core.eventcodegen/trunk/org.jiemamy.core.eventcodegen/src/main/resources/ChangeSupportImpl.vm 2008-11-18 16:51:41 UTC (rev 2170) @@ -28,12 +28,13 @@ * @author shin1ogawa */ public class ${modelClassName}ChangeSupportImpl extends AbstractModelChangeSupport implements ModelChangeSupport { - +#if(${properties.size()} > 0) private static Logger logger = LoggerFactory.getLogger(ModelChangeSupport.class); /** イベント発火元となるModel */ private WeakReference<${modelClassName}> eventTarget; +#end #foreach($property in $properties) /** @@ -49,9 +50,9 @@ * {@inheritDoc} */ public void collectionChanged(ObservableCollectionChangeEvent<${property.collectionClassSimpleName}<#if(${property.map} != false)${property.mapKeyClassSimpleName}, #end${property.elementClassSimpleName}>, ${property.elementClassSimpleName}> event) { - if (event.getTiming() != ObservableCollectionChangeEvent.Timing.BEFORE_ADD - && event.getTiming() != ObservableCollectionChangeEvent.Timing.BEFORE_REMOVE - && event.getTiming() != ObservableCollectionChangeEvent.Timing.BEFORE_SET) { + if (event.getTiming() != Timing.BEFORE_ADD + && event.getTiming() != Timing.BEFORE_REMOVE + && event.getTiming() != Timing.BEFORE_SET) { if (event.getTiming() == Timing.COLLECTION_CHANGED) { event.setSource(event.getModel()); } else { @@ -86,11 +87,13 @@ * @category instance creation */ public ${modelClassName}ChangeSupportImpl(${modelClassName} source) { +#if(${properties.size()} > 0) ${modelClassName}Accessor accessor = (${modelClassName}Accessor) source; + eventTarget = new WeakReference<${modelClassName}>(source); +#end source.getAdapter(Observable.class).addModelChangeListener(modelChangeListener); - eventTarget = new WeakReference<${modelClassName}>(source); #foreach($property in $properties) - ((${property.observableCollectionClassSimpleName}<#if(${property.map} != false)${property.mapKeyClassSimpleName}, #end${property.elementClassSimpleName}>) accessor.get${property.nameUpper}()).addListener(${property.name}CollectionChangeListener); + ((${property.observableCollectionClassSimpleName}<#if(${property.map} != false)${property.mapKeyClassSimpleName}, #end${property.elementClassSimpleName}>) accessor.${property.getterName}()).addListener(${property.name}CollectionChangeListener); #end }