From d057855ea14ff21c0720df04881288e283fc1717 Mon Sep 17 00:00:00 2001
From: Niklas Fors <niklas.fors@cs.lth.se>
Date: Fri, 6 Jul 2018 11:12:44 +0200
Subject: [PATCH] Make returned list immutable and minor refactorings

---
 spec/jastadd/Backend.jadd | 54 +++++++++++++++++----------------------
 test/Test.java            | 39 ++++++++++++++++++++++++++--
 2 files changed, 61 insertions(+), 32 deletions(-)

diff --git a/spec/jastadd/Backend.jadd b/spec/jastadd/Backend.jadd
index e042714..763091d 100644
--- a/spec/jastadd/Backend.jadd
+++ b/spec/jastadd/Backend.jadd
@@ -72,7 +72,8 @@ aspect BackendAspect {
 	}
 
 	public void Program.generateAspect(StringBuilder sb) {
-		sb.append("import java.util.*;\n");
+		sb.append("import java.util.ArrayList;\n");
+		sb.append("import java.util.Collections;\n");
 		sb.append("aspect RelAstAPI {\n");
 		for (TypeDecl td: getTypeDecls()) {
 			if (td.needsConstructor()) {
@@ -142,10 +143,7 @@ aspect BackendDirectedAPI {
 	}
 	public void RelationComponent.generateDirectedZeroOneAPI(StringBuilder sb, boolean optional) {
 		// 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");
+		generateGetOne(sb);
 
 		// Set
 		sb.append(ind(1) + "public void " + toTypeDecl());
@@ -159,11 +157,7 @@ aspect BackendDirectedAPI {
 
 	public void ManyRelationComponent.generateDirectedAPI(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");
+		generateGetMany(sb);
 
 		// Add
 		sb.append(ind(1) + "public void " + toTypeDecl() + ".addTo");
@@ -188,6 +182,13 @@ aspect BackendDirectedAPI {
 		sb.append(ind(1) + "}\n");
 	}
 
+	public void RelationComponent.generateGetOne(StringBuilder sb) {
+		sb.append(ind(1) + "public " + ofTypeDecl() + " " + toTypeDecl());
+		sb.append("." + name() + "() {\n");
+		sb.append(ind(2) + "return get" + getImplAttributeName() + "();\n");
+		sb.append(ind(1) + "}\n");
+	}
+
 	public void RelationComponent.generateExtraOptAPI(StringBuilder sb) {
 		// has
 		sb.append(ind(1) + "public boolean " + toTypeDecl());
@@ -201,6 +202,15 @@ aspect BackendDirectedAPI {
 		sb.append(ind(2) + "set" + nameCapitalized() + "(null);\n");
 		sb.append(ind(1) + "}\n");
 	}
+
+	public void RelationComponent.generateGetMany(StringBuilder sb) {
+		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 ? Collections.unmodifiableList(l) : Collections.emptyList();\n");
+		sb.append(ind(1) + "}\n");
+	}
 }
 
 aspect BackendBidirectionalAPI {
@@ -246,10 +256,7 @@ aspect BackendBidirectionalAPI {
 
 	public void RelationComponent.generateBiOneOne(StringBuilder sb, boolean isOpt) {
 		// 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");
+		generateGetOne(sb);
 
 		// Set
 		sb.append(ind(1) + "public void " + toTypeDecl());
@@ -280,12 +287,7 @@ aspect BackendBidirectionalAPI {
 
 	public void RelationComponent.generateBiManyMany(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");
+		generateGetMany(sb);
 
 		// Add
 		sb.append(ind(1) + "public void " + toTypeDecl() + ".addTo");
@@ -324,12 +326,7 @@ aspect BackendBidirectionalAPI {
 
 	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");
+		generateGetMany(sb);
 
 		// Add
 		sb.append(ind(1) + "public void " + toTypeDecl() + ".addTo");
@@ -367,10 +364,7 @@ aspect BackendBidirectionalAPI {
 
 	public void RelationComponent.generateBiOneMany(StringBuilder sb, boolean isOpt) {
 		// 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");
+		generateGetOne(sb);
 
 		// Set
 		sb.append(ind(1) + "public void " + toTypeDecl() + ".set" + nameCapitalized()
diff --git a/test/Test.java b/test/Test.java
index bf24395..a40c246 100644
--- a/test/Test.java
+++ b/test/Test.java
@@ -29,6 +29,8 @@ public class Test {
 		testBi8();
 		testBi9();
 
+		testImmutableList();
+
 		System.out.println("TESTS OK");
 	}
 
@@ -50,7 +52,7 @@ public class Test {
 
 		try {
 			a3.setDi1(null);
-			check(false, "should throw exception");
+			assertException();
 		} catch (Exception e) {
 			// OK
 		}
@@ -231,7 +233,7 @@ public class Test {
 
 		try {
 			a2.setBi3(null);
-			check(false, "exception should be thrown");
+			assertException();
 		} catch (Exception e) {
 			// OK
 		}
@@ -504,6 +506,36 @@ public class Test {
 	}
 
 
+	public void testImmutableList() {
+		setup();
+
+		a1.addToDi3(b1);
+		a1.addToDi3(b2);
+		try {
+			a1.di3().add(b3);
+			assertException();
+		} catch (Exception e) {
+			// OK
+		}
+
+		a1.addToBi7(b1);
+		a1.addToBi7(b2);
+		try {
+			a1.bi7().add(b3);
+			assertException();
+		} catch (Exception e) {
+			// OK
+		}
+
+		a1.addToBi9(b1);
+		a1.addToBi9(b2);
+		try {
+			a1.bi9().add(b3);
+			assertException();
+		} catch (Exception e) {
+			// OK
+		}
+	}
 
 	private void setup() {
 		r = new Root();
@@ -522,6 +554,9 @@ public class Test {
 		r.addB(b3);
 	}
 
+	private void assertException() {
+		check(false, "should throw exception");
+	}
 	private void assertTrue(boolean b) {
 		check(b, "value should be true (is false)");
 	}
-- 
GitLab