diff --git a/src/main/java/designPatternExtensions/designPattern/Mediator2.java b/src/main/java/designPatternExtensions/designPattern/Mediator2.java index 6bb9e85..8ea4c0b 100644 --- a/src/main/java/designPatternExtensions/designPattern/Mediator2.java +++ b/src/main/java/designPatternExtensions/designPattern/Mediator2.java @@ -13,6 +13,10 @@ //concretePartyMemberがActionをおこすと、PartyImplからほかのPartyMemberの処理を呼び出す //https://github.com/iluwatar/java-design-patterns/tree/master/mediator +//srcとdstが同じ型の転送の場合、weaveDeltaが生成したメソッドの中に、そのクラス固有の兄弟フィールドへの +//参照が入り込んでしまう(partyImpl→thisへの読み替え、action→パラメータ化)で対応できる +//MediatorInsertionで対応するべきかそれより前の問題か + public class Mediator2 implements DesignPattern { public DataTransferDesign create() throws IllegalRelationException { @@ -34,7 +38,9 @@ // DependencyInversion di3 = new DependencyInversion(partyImpl, party); // design.addDependencyInversion(di3); - MediatorInsertion mi = new MediatorInsertion(concretePartyMember, concretePartyMember, partyImpl, PushPullValue.PUSH); + ObjectNode imp2 = new ObjectNode("PartyImpl2"); + + MediatorInsertion mi = new MediatorInsertion(concretePartyMember, concretePartyMember, imp2, PushPullValue.PUSH); design.addMediatorInsertion(mi); // MediatorInsertion mi2 = new MediatorInsertion(main, concretePartyMember, partyImpl, PushPullValue.PUSH); diff --git a/src/main/java/generators/ASTGenerator.java b/src/main/java/generators/ASTGenerator.java index bf0d91f..7fdd86f 100644 --- a/src/main/java/generators/ASTGenerator.java +++ b/src/main/java/generators/ASTGenerator.java @@ -63,7 +63,6 @@ return codebase; } } - public static Codebase weavePrimitiveDelta(Codebase codebase, PrimitiveDelta primitiveDelta) { if (primitiveDelta instanceof PrimitivePullDelta) { codebase = weavePrimitivePullDelta(codebase, (PrimitivePullDelta) primitiveDelta); @@ -334,105 +333,173 @@ models.algebra.Type dstType = codebase.getComponentType(dstName); - // Create a Mediator class and add a field of type dst TypeDeclaration mediatorClass = createClass(codebase, mediatorName); models.algebra.Type mediatorType = codebase.getComponentType(mediatorName); - FieldDeclaration dstField = createField(mediatorClass, dstFieldName, dstType); + TypeDeclaration srcClass = createClass(codebase, srcName); + TypeDeclaration dstClass = createClass(codebase, dstName); + + FieldDeclaration srcDstMapField = null; + for (FieldDeclaration field: srcClass.getFields()) { + if (field.getType() instanceof MapType) { + MapType mapType = (MapType) field.getType(); + if (mapType.getValueType() != null && mapType.getValueType().getTypeName().equals(dstType.getTypeName())) { + srcDstMapField = field; + break; + } + } + } + boolean toMany = srcDstMapField != null; + + FieldDeclaration dstField; + if (toMany) { + MapType srcMapType = (MapType) srcDstMapField.getType(); + FieldDeclaration existingMediatorMapField = null; + for (FieldDeclaration field: mediatorClass.getFields()) { + if (field.getType() instanceof MapType) { + MapType mapType = (MapType) field.getType(); + if (mapType.getValueType() != null && mapType.getValueType().getTypeName().equals(dstType.getTypeName()) + && mapType.getKeyType().getTypeName().equals(srcMapType.getKeyType().getTypeName())) { + existingMediatorMapField = field; + break; + } + } + } + dstField = (existingMediatorMapField != null) + ? existingMediatorMapField + : createField(mediatorClass, srcDstMapField.getName(), srcMapType); + } else { + dstField = createField(mediatorClass, dstFieldName, dstType); + } // Add Constructor MethodDeclaration constructor = createConstructor(mediatorClass); - VariableDeclaration dstParam = new VariableDeclaration(dstType, dstFieldName); - constructor.addParameter(dstParam); - FieldAccess dstFieldAccess = new FieldAccess(new ThisExpression(), dstField.getName()); - Assignment dstAssignment = new Assignment(dstFieldAccess, new Variable(dstFieldName)); // this.b = b; - constructor.addUniqueStatement(new ExpressionStatement(dstAssignment)); + if (!hasParameterNamed(constructor, dstField.getName())) { + VariableDeclaration dstParam = new VariableDeclaration(dstField.getType(), dstField.getName()); + constructor.addParameter(dstParam); + FieldAccess dstFieldAccess = new FieldAccess(new ThisExpression(), dstField.getName()); + Assignment dstAssignment = new Assignment(dstFieldAccess, new Variable(dstField.getName())); + constructor.addUniqueStatement(new ExpressionStatement(dstAssignment)); + } - // Add delegation methods to the Mediator that forward calls to dst's public methods - TypeDeclaration dstClass = createClass(codebase, dstName); - for (MethodDeclaration method: dstClass.getMethods()) { - if (method.isConstructor()) continue; - MethodDeclaration delegateMethod = createMethod(mediatorClass, method.getName()); - delegateMethod.setReturnType(method.getReturnType()); - List args = new ArrayList<>(); - if (method.getParameters() != null) { - for (VariableDeclaration param: method.getParameters()) { - delegateMethod.addParameter(param); - args.add(new Variable(param.getName())); + if (!toMany) { + for (MethodDeclaration method: dstClass.getMethods()) { + if (method.isConstructor()) continue; + MethodDeclaration delegateMethod = createMethod(mediatorClass, method.getName()); + delegateMethod.setReturnType(method.getReturnType()); + List args = new ArrayList<>(); + if (method.getParameters() != null) { + for (VariableDeclaration param: method.getParameters()) { + delegateMethod.addParameter(param); + args.add(new Variable(param.getName())); + } + } + FieldAccess dstAccess = new FieldAccess(dstField.getName()); + MethodInvocation callDst = new MethodInvocation(dstAccess, method.getName(), args); + if (method.getReturnType() != null) { + ReturnStatement returnStatement = new ReturnStatement(); + returnStatement.setExpression(callDst); + delegateMethod.addUniqueStatement(returnStatement); + } else { + delegateMethod.addUniqueStatement(new ExpressionStatement(callDst)); } } - FieldAccess dstAccess = new FieldAccess(dstField.getName()); - MethodInvocation callDst = new MethodInvocation(dstAccess, method.getName(), args); - if (method.getReturnType() != null) { - ReturnStatement returnStatement = new ReturnStatement(); - returnStatement.setExpression(callDst); - delegateMethod.addUniqueStatement(returnStatement); + } + + FieldDeclaration srcFieldToReplace = toMany ? srcDstMapField : null; + if (!toMany) { + for (FieldDeclaration field: srcClass.getFields()) { + if (field.getType() != null && field.getType().getTypeName().equals(dstType.getTypeName())) { + srcFieldToReplace = field; + break; + } + } + } + + if (srcFieldToReplace != null) { + FieldDeclaration existingMediatorField = null; + for (FieldDeclaration field: srcClass.getFields()) { + if (field != srcFieldToReplace && field.getType() != null + && field.getType().getTypeName().equals(mediatorType.getTypeName())) { + existingMediatorField = field; + break; + } + } + String oldFieldName = srcFieldToReplace.getName(); + if (existingMediatorField != null) { + srcClass.removeField(srcFieldToReplace); + mediatorFieldName = existingMediatorField.getName(); } else { - delegateMethod.addUniqueStatement(new ExpressionStatement(callDst)); + srcFieldToReplace.setType(mediatorType); + srcFieldToReplace.setName(mediatorFieldName); } - } - // Replace the dst-type field in src with a Mediator-type field - TypeDeclaration srcClass = createClass(codebase, srcName); - for (FieldDeclaration field: srcClass.getFields()) { - if (field.getType() != null && field.getType().getTypeName().equals(dstType.getTypeName())) { - field.setType(mediatorType); - field.setName(mediatorFieldName); - } else if (field.getType() instanceof MapType) { - MapType mapType = (MapType) field.getType(); - if (mapType.getValueType() != null && mapType.getValueType().getTypeName().equals(dstType.getTypeName())) { - field.setType(codebase.getMapType(mapType.getKeyType().getTypeName(), mediatorName)); - field.setName(mediatorFieldName); - } + // Add Mediator Setter + MethodDeclaration mediatorSetter = createMethod(srcClass, setterPrefix + mediatorName); + if (mediatorSetter.getParameters() == null || mediatorSetter.getParameters().isEmpty()) { + VariableDeclaration mediatorParam = new VariableDeclaration(mediatorType, mediatorFieldName); + mediatorSetter.addParameter(mediatorParam); + FieldAccess mediatorFieldAccess = new FieldAccess(new ThisExpression(), mediatorFieldName); + Assignment mediatorAssignment = new Assignment(mediatorFieldAccess, new Variable(mediatorFieldName)); + mediatorSetter.addUniqueStatement(new ExpressionStatement(mediatorAssignment)); } - } - // Add Mediator Setter - MethodDeclaration mediatorSetter = createMethod(srcClass, setterPrefix + mediatorName); - VariableDeclaration mediatorParam = new VariableDeclaration(mediatorType, mediatorFieldName); - mediatorSetter.addParameter(mediatorParam); - FieldAccess mediatorFieldAccess = new FieldAccess(new ThisExpression(), mediatorFieldName); - Assignment mediatorAssignment = new Assignment(mediatorFieldAccess, new Variable(mediatorFieldName)); // this.me = me; - mediatorSetter.addUniqueStatement(new ExpressionStatement(mediatorAssignment)); - - // Change the constructor parameter type in src from dst to Mediator, and rename the parameter accordingly - for (MethodDeclaration method: srcClass.getMethods()) { - if (method.isConstructor() && method.getParameters() != null) { - for (VariableDeclaration param: method.getParameters()) { - if (param.getType() != null && param.getType().getTypeName().equals(dstType.getTypeName())) { - param.setType(mediatorType); - param.setName(mediatorFieldName); + // Change the constructor parameter type in src from dst to Mediator, and rename the parameter accordingly + for (MethodDeclaration method: srcClass.getMethods()) { + if (method.isConstructor() && method.getParameters() != null) { + for (VariableDeclaration param: method.getParameters()) { + if (param.getType() != null && param.getType().getTypeName().equals(dstType.getTypeName())) { + param.setType(mediatorType); + param.setName(mediatorFieldName); + } } } } - } - // Replace all references to the dst field with references to the mediator field in the bodies of src's methods - for (MethodDeclaration method: srcClass.getMethods()) { - if (method.getBody() == null) continue; - for (Statement statement: method.getBody().getStatements2()) { - replaceFieldNameInStatement(statement, dstFieldName, mediatorFieldName); - } - } - - // Replace return type and MapType value type matching dst type with Mediator type in all classes - for (CompilationUnit cu: codebase.getCompilationUnits()) { - TypeDeclaration cls = cu.types().getFirst(); - for (MethodDeclaration method: cls.getMethods()) { - if (!method.isConstructor() && method.getReturnType() != null) { - if (method.getReturnType().getTypeName().equals(dstType.getTypeName())) { - method.setReturnType(mediatorType); - } + List methodsToMove = new ArrayList<>(); + for (MethodDeclaration method: srcClass.getMethods()) { + if (method.isConstructor()) continue; + if (methodReferencesField(method, oldFieldName)) { + methodsToMove.add(method); } } - for (FieldDeclaration field: cls.getFields()) { - if (field.getType() instanceof MapType) { - MapType mapType = (MapType) field.getType(); - if (mapType.getValueType() != null && mapType.getValueType().getTypeName().equals(dstType.getTypeName())) { - field.setType(codebase.getMapType(mapType.getKeyType().getTypeName(), mediatorName)); + for (MethodDeclaration method: methodsToMove) { + srcClass.removeMethod(method); + MethodDeclaration existingOnMediator = null; + for (MethodDeclaration existing: mediatorClass.getMethods()) { + if (existing.getName().equals(method.getName())) { existingOnMediator = existing; break; } + } + if (existingOnMediator == null) { + mediatorClass.addMethod(method); + } + + MethodDeclaration stub = createMethod(srcClass, method.getName()); + stub.setReturnType(method.getReturnType()); + List args = new ArrayList<>(); + if (method.getParameters() != null) { + for (VariableDeclaration param: method.getParameters()) { + stub.addParameter(param); + args.add(new Variable(param.getName())); } } + FieldAccess mediatorAccess = new FieldAccess(mediatorFieldName); + MethodInvocation callMediator = new MethodInvocation(mediatorAccess, method.getName(), args); + if (method.getReturnType() != null) { + ReturnStatement returnStatement = new ReturnStatement(); + returnStatement.setExpression(callMediator); + stub.addUniqueStatement(returnStatement); + } else { + stub.addUniqueStatement(new ExpressionStatement(callMediator)); + } + } + + for (MethodDeclaration method: srcClass.getMethods()) { + if (method.getBody() == null) continue; + for (Statement statement: method.getBody().getStatements2()) { + replaceFieldNameInStatement(statement, oldFieldName, mediatorFieldName); + } } } + return codebase; } @@ -623,6 +690,18 @@ } else if (statement instanceof ReturnStatement) { Expression expr = ((ReturnStatement) statement).getExpression(); return expr != null && expressionReferencesField(expr, fieldName); + } else if (statement instanceof EnhancedForStatement) { + EnhancedForStatement forStatement = (EnhancedForStatement) statement; + if (expressionReferencesField(forStatement.getExpression(), fieldName)) return true; + Statement body = forStatement.getBody(); + if (body == null) return false; + if (body instanceof Block) { + for (Statement inner: ((Block) body).getStatements2()) { + if (statementReferencesField(inner, fieldName)) return true; + } + return false; + } + return statementReferencesField(body, fieldName); } return false; }