diff --git a/spec/jastadd/Backend.jadd b/spec/jastadd/Backend.jadd index bd2e2903586c1bfdf76f0c3850fee9e53a753504..5d4404445f0ea075eb6f3e4d6d48ef53d304603c 100644 --- a/spec/jastadd/Backend.jadd +++ b/spec/jastadd/Backend.jadd @@ -200,37 +200,39 @@ aspect BackendBidirectionalAPI { if (l.multiplicityOne()) { if (r.multiplicityOne()) { - l.generateBiOne(sb, false); - r.generateBiOne(sb, false); + l.generateBiOneOne(sb, false); + r.generateBiOneOne(sb, false); } else if (r.multiplicityOpt()) { - l.generateBiOne(sb, false); - r.generateBiOne(sb, true); + l.generateBiOneOne(sb, false); + r.generateBiOneOne(sb, true); } else if (r.multiplicityMany()) { - + l.generateBiOneMany(sb); + r.generateBiManyOne(sb); } } else if (l.multiplicityOpt()) { if (r.multiplicityOne()) { - l.generateBiOne(sb, true); - r.generateBiOne(sb, false); + l.generateBiOneOne(sb, true); + r.generateBiOneOne(sb, false); } else if (r.multiplicityOpt()) { - l.generateBiOne(sb, true); - r.generateBiOne(sb, true); + l.generateBiOneOne(sb, true); + r.generateBiOneOne(sb, true); } else if (r.multiplicityMany()) { } } else if (l.multiplicityMany()) { if (r.multiplicityOne()) { - + l.generateBiManyOne(sb); + r.generateBiOneMany(sb); } else if (r.multiplicityOpt()) { } else if (r.multiplicityMany()) { - l.generateBiMany(sb); - r.generateBiMany(sb); + l.generateBiManyMany(sb); + r.generateBiManyMany(sb); } } } - public void RelationComponent.generateBiOne(StringBuilder sb, boolean isOpt) { + public void RelationComponent.generateBiOneOne(StringBuilder sb, boolean isOpt) { // Get sb.append(ind(1) + "public " + ofTypeDecl() + " " + toTypeDecl()); sb.append("." + name() + "() {\n"); @@ -268,7 +270,7 @@ aspect BackendBidirectionalAPI { } } - public void RelationComponent.generateBiMany(StringBuilder sb) { + public void RelationComponent.generateBiManyMany(StringBuilder sb) { // Get sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl()); sb.append("." + name() + "() {\n"); @@ -310,6 +312,79 @@ aspect BackendBidirectionalAPI { sb.append(ind(2) + "}\n"); sb.append(ind(1) + "}\n"); } + + + public void RelationComponent.generateBiManyOne(StringBuilder sb) { + // Get + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl()); + sb.append("." + name() + "() {\n"); + sb.append(ind(2) + "ArrayList<" + ofTypeDecl() + "> l = get" + + getImplAttributeName() + "();\n"); + sb.append(ind(2) + "return l != null ? l : Collections.emptyList();\n"); + sb.append(ind(1) + "}\n"); + + // Add + sb.append(ind(1) + "public void " + toTypeDecl() + ".addTo"); + sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + "if (o != null && o.get" + otherSide().getImplAttributeName() + "() != null) {\n"); + sb.append(ind(3) + "ArrayList<" + ofTypeDecl() + "> list2 = o.get" + + otherSide().getImplAttributeName() + "().get" + getImplAttributeName() + "();\n"); + sb.append(ind(3) + "if (list2.remove(o))\n"); + sb.append(ind(4) + "o.get" + otherSide().getImplAttributeName() + + "().set" + getImplAttributeName() + "(list2);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "ArrayList<" + ofTypeDecl() + "> list = get" + getImplAttributeName() + "();\n"); + sb.append(ind(2) + "if (list == null) {\n"); + sb.append(ind(3) + "list = new ArrayList<>();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "list.add(o);\n"); + sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n"); + sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + sb.append(ind(1) + "}\n"); + + // Remove + sb.append(ind(1) + "public void " + toTypeDecl() + ".removeFrom"); + sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + "ArrayList<" + ofTypeDecl() + "> list = get" + getImplAttributeName() + "();\n"); + sb.append(ind(2) + "if (list != null && list.remove(o)) {\n"); + sb.append(ind(3) + "set" + getImplAttributeName() + "(list);\n"); + sb.append(ind(3) + "if (o.get" + otherSide().getImplAttributeName() + "() == this) {\n"); + sb.append(ind(4) + "o.set" + otherSide().getImplAttributeName() + "(null);\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(1) + "}\n"); + } + + public void RelationComponent.generateBiOneMany(StringBuilder sb) { + // Get + sb.append(ind(1) + "public " + ofTypeDecl() + " " + toTypeDecl()); + sb.append("." + name() + "() {\n"); + sb.append(ind(2) + "return get" + getImplAttributeName() + "();\n"); + sb.append(ind(1) + "}\n"); + + // Set + sb.append(ind(1) + "public void " + toTypeDecl() + ".set" + nameCapitalized() + + "(" + ofTypeDecl() + " o) {\n"); + sb.append(ind(2) + "assertNotNull(o);\n"); + sb.append(ind(2) + "if (get" + getImplAttributeName() + "() != null) {\n"); + sb.append(ind(3) + "ArrayList<" + toTypeDecl() + "> list2 = get" + getImplAttributeName() + + "()." + "get" + otherSide().getImplAttributeName() + "();\n"); + sb.append(ind(3) + "list2.remove(this);\n"); + sb.append(ind(3) + "get" + getImplAttributeName() + "()." + "set" + + otherSide().getImplAttributeName() + "(list2);\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n"); + sb.append(ind(2) + "ArrayList<" + toTypeDecl() + "> list = o.get" + + otherSide().getImplAttributeName() + "();\n"); + sb.append(ind(2) + "if (list == null) {\n"); + sb.append(ind(3) + "list = new ArrayList<>();\n"); + sb.append(ind(2) + "}\n"); + sb.append(ind(2) + "list.add(this);\n"); + sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(list);\n"); + sb.append(ind(1) + "}\n"); + } } diff --git a/test/Test.java b/test/Test.java index 10651e44e3757b5b59320c16ad4a54a6b40c85e2..e63a480e945e26c38a1fca112009585e4dca7463 100644 --- a/test/Test.java +++ b/test/Test.java @@ -191,6 +191,48 @@ public class Test { * rel A.bi3 <-> B.bi3*; */ private void testBi3() { + setup(); + a2.setBi3(b2); + + assertNull(a1.bi3()); + assertSame(a2.bi3(), b2); + assertEquals(b1.bi3(), Arrays.asList()); + assertEquals(b2.bi3(), Arrays.asList(a2)); + assertEquals(b3.bi3(), Arrays.asList()); + + a2.setBi3(b3); + + assertNull(a1.bi3()); + assertSame(a2.bi3(), b3); + assertEquals(b1.bi3(), Arrays.asList()); + assertEquals(b2.bi3(), Arrays.asList()); + assertEquals(b3.bi3(), Arrays.asList(a2)); + + a1.setBi3(b3); + a3.setBi3(b3); + + assertSame(a1.bi3(), b3); + assertSame(a2.bi3(), b3); + assertSame(a3.bi3(), b3); + assertEquals(b1.bi3(), Arrays.asList()); + assertEquals(b2.bi3(), Arrays.asList()); + assertEquals(b3.bi3(), Arrays.asList(a2, a1, a3)); + + a2.setBi3(b1); + + assertSame(a1.bi3(), b3); + assertSame(a2.bi3(), b1); + assertSame(a3.bi3(), b3); + assertEquals(b1.bi3(), Arrays.asList(a2)); + assertEquals(b2.bi3(), Arrays.asList()); + assertEquals(b3.bi3(), Arrays.asList(a1, a3)); + + try { + a2.setBi3(null); + check(false, "exception should be thrown"); + } catch (Exception e) { + // OK + } } @@ -281,6 +323,47 @@ public class Test { * rel A.bi7* <-> B.bi7; */ private void testBi7() { + setup(); + a2.addToBi7(b2); + + assertEquals(a1.bi7(), Arrays.asList()); + assertEquals(a2.bi7(), Arrays.asList(b2)); + assertNull(b1.bi7()); + assertSame(b2.bi7(), a2); + assertNull(b3.bi7()); + + a2.addToBi7(b3); + a1.addToBi7(b2); + + assertEquals(a1.bi7(), Arrays.asList(b2)); + assertEquals(a2.bi7(), Arrays.asList(b3)); + assertNull(b1.bi7()); + assertSame(b2.bi7(), a1); + assertSame(b3.bi7(), a2); + + a1.addToBi7(b1); + + assertEquals(a1.bi7(), Arrays.asList(b2, b1)); + assertEquals(a2.bi7(), Arrays.asList(b3)); + assertSame(b1.bi7(), a1); + assertSame(b2.bi7(), a1); + assertSame(b3.bi7(), a2); + + a1.addToBi7(b1); + + assertEquals(a1.bi7(), Arrays.asList(b2, b1)); + assertEquals(a2.bi7(), Arrays.asList(b3)); + assertSame(b1.bi7(), a1); + assertSame(b2.bi7(), a1); + assertSame(b3.bi7(), a2); + + a1.removeFromBi7(b1); + + assertEquals(a1.bi7(), Arrays.asList(b2)); + assertEquals(a2.bi7(), Arrays.asList(b3)); + assertNull(b1.bi7()); + assertSame(b2.bi7(), a1); + assertSame(b3.bi7(), a2); }