Merge commit 'b0d35359aa83b498d87d32dcd0c20d8defd0e8a7'
diff --git a/features/org.eclipse.objectteams.otdt.source.feature/feature.xml b/features/org.eclipse.objectteams.otdt.source.feature/feature.xml
index eca2051..b04cf3b 100644
--- a/features/org.eclipse.objectteams.otdt.source.feature/feature.xml
+++ b/features/org.eclipse.objectteams.otdt.source.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.objectteams.otdt.source.feature"
       label="%featureName"
-      version="2.3.0.qualifier"
+      version="2.3.1.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/objectteams">
diff --git a/features/org.eclipse.objectteams.otequinox.feature/feature.xml b/features/org.eclipse.objectteams.otequinox.feature/feature.xml
index 09cb1d1..4871187 100644
--- a/features/org.eclipse.objectteams.otequinox.feature/feature.xml
+++ b/features/org.eclipse.objectteams.otequinox.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.objectteams.otequinox"
       label="%featureName"
-      version="2.3.0.qualifier"
+      version="2.3.1.qualifier"
       provider-name="%providerName"
       plugin="org.eclipse.objectteams.otequinox"
       colocation-affinity="org.eclipse.rcp">
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractNullAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractNullAnnotationTest.java
index b1be1c8..8d10ee5 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractNullAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractNullAnnotationTest.java
@@ -123,9 +123,15 @@
 				// runtime options
 			    JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
 	}
+//{ObjectTeams: make visible to downstream:
+	protected
+// SH}
 	void runNegativeTestWithLibs(String[] testFiles, Map customOptions, String expectedErrorLog) {
 		runNegativeTestWithLibs(false /* flush output directory */,	testFiles, customOptions, expectedErrorLog);
 	}
+//{ObjectTeams: make visible to downstream:
+	protected
+// SH}
 	void runConformTestWithLibs(String[] testFiles, Map customOptions, String expectedCompilerLog) {
 		runConformTestWithLibs(false /* flush output directory */, testFiles, customOptions, expectedCompilerLog);
 	}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/LocalVMLauncher.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/LocalVMLauncher.java
index e3de69a..6f5fa63 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/LocalVMLauncher.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/LocalVMLauncher.java
@@ -60,10 +60,12 @@
 	if (vmName != null && vmName.indexOf("JRockit") != -1) {
 		return new JRockitVMLauncher();
 	}
-	final String osName = System.getProperty("os.name");
-	if (osName.startsWith("Mac")) {
-		return new MacVMLauncher();
-	}
+//{ObjectTeams: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=413850
+//	final String osName = System.getProperty("os.name");
+//	if (osName.startsWith("Mac")) {
+//		return new MacVMLauncher();
+//	}
+// SH}
 	File file = new File(Util.getJREDirectory() + "/lib/rt.jar");
 	if (file.exists()) {
 		return new StandardVMLauncher();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
index e4da37c..83b3cd0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
@@ -24,6 +24,7 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.LiftingTypeReference;
 
 /**
  * OTDT changes:
@@ -97,6 +98,10 @@
 				Annotation.isTypeUseCompatible(this.type, scope, this.annotations);
 				scope.validateNullAnnotation(this.binding.tagBits, this.type, this.annotations);
 			}
+//{ObjectTeams: LTR needs to do more work:
+			if (this.type instanceof LiftingTypeReference)
+				((LiftingTypeReference) this.type).updateBindingAndCheckNullness(scope);
+//SH}
 		}
 		this.binding.declaration = this;
 		return this.binding.type; // might have been updated during resolveAnnotations (for typeAnnotations)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
index 9e244bd..c90401a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
@@ -36,7 +36,12 @@
 	public EqualExpression(Expression left, Expression right,int operator) {
 		super(left,right,operator);
 	}
+//{ObjectTeams: made overridable:
+/*orig:
 	private void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
+  :giro */
+	protected void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
+// SH}
 
 		// collect null status of child nodes:
 		int rightStatus = this.right.nullStatus(flowInfo, flowContext);
@@ -193,9 +198,6 @@
 			result = FlowInfo.conditional(result.copy(), result.copy());
 			// TODO (maxime) check, reintroduced copy
 		}
-//{ObjectTeams: no warnings/errors for generated (null-)checks:
-	  if (!this.isGenerated)
-// SH}
 		checkNullComparison(currentScope, flowContext, result, result.initsWhenTrue(), result.initsWhenFalse());
 		return result;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
index 1731a3a..affb2ef 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
@@ -44,7 +44,6 @@
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Scope;
 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
-import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
@@ -53,6 +52,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticOTTargetMethod;
 import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementor;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.FieldModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.util.RoleTypeCreator;
@@ -740,7 +740,7 @@
 				if (this.syntheticAccessors == null)
 					this.syntheticAccessors = new MethodBinding[2];
 				this.syntheticAccessors[isSetter ? FieldReference.WRITE : FieldReference.READ] =
-						new SyntheticMethodBinding(callout.roleMethodSpec.resolvedMethod, SyntheticMethodBinding.InferredCalloutToField);
+											new SyntheticOTTargetMethod.CalloutToField(callout.roleMethodSpec.resolvedMethod);
 				fieldBinding = ((FieldAccessSpec)callout.baseMethodSpec).resolvedField;
 				this.binding = fieldBinding;
 				setDepth(fieldBinding.isStatic() ? 1 : 0); // static c-t-f needs to pass the enclosing team
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
index 8e7bb3f..7abcefa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
@@ -18,6 +18,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
 import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
 import org.eclipse.jdt.internal.compiler.lookup.Scope;
@@ -82,15 +83,19 @@
 				Scope currentScope = scope;
 				while (currentScope != null) {
 					if (currentScope instanceof OTClassScope) {
-						Scope baseScope = ((OTClassScope)currentScope).getBaseImportScope();
+						CompilationUnitScope baseScope = ((OTClassScope)currentScope).getBaseImportScope(scope);
 						if (baseScope != null) {
-							TypeBinding previousType = this.resolvedType;
-							this.resolvedType = null;
-							TypeBinding baseImportedType = getTypeBinding(baseScope);
-							if (baseImportedType != null && baseImportedType.isValidBinding())
-								return this.resolvedType = baseImportedType;
-							this.resolvedType = previousType;
-							break;
+							try {
+								TypeBinding previousType = this.resolvedType;
+								this.resolvedType = null;
+								TypeBinding baseImportedType = getTypeBinding(baseScope);
+								if (baseImportedType != null && baseImportedType.isValidBinding())
+									return this.resolvedType = baseImportedType;
+								this.resolvedType = previousType;
+								break;
+							} finally {
+								baseScope.originalScope = null;
+							}
 						}
 					}
 					currentScope = currentScope.parent;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
index 4f9c41c..b1cd758 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
@@ -73,7 +73,6 @@
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions.WeavingScheme;
-import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
@@ -109,6 +108,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.AnchorMapping;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticOTTargetMethod;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticRoleBridgeMethodBinding;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.WeakenedTypeBinding;
 import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementor;
@@ -117,7 +117,6 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.copyinheritance.CopyInheritance.RoleConstructorCall;
 import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.StandardElementGenerator;
-import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator;
 import org.eclipse.objectteams.otdt.internal.core.compiler.util.RoleTypeCreator;
 
 /**
@@ -1054,22 +1053,13 @@
 				if (this.accessId == -1) // happens for BaseAllocationExpression with role-as-base
 					this.accessId = scope.enclosingSourceType().roleModel.addInaccessibleBaseMethod(this.binding);
 				// pretend that accessor method were already there:
-				this.binding = new MethodBinding(this.binding, this.binding.declaringClass.getRealClass());
 				if (weavingScheme == WeavingScheme.OTDRE) {
-					if (this.binding.isStatic())
-						this.binding.selector = CalloutImplementorDyn.OT_ACCESS_STATIC;
-					else
-						this.binding.selector = CalloutImplementorDyn.OT_ACCESS;
-					TypeBinding originalReturnType = this.binding.returnType;
-					if (originalReturnType.id != TypeIds.T_void) {
-						if (originalReturnType.isBaseType()) {
-							this.valueCast = scope.getType(AstGenerator.boxTypeName((BaseTypeBinding) originalReturnType), 3);
-							computeConversion(scope, this.valueCast, originalReturnType);
-						} else {
-							this.valueCast = originalReturnType;
-						}
-					}
+					MethodBinding accessor = CalloutImplementorDyn.ensureAccessor(scope, this.binding.declaringClass, this.binding.isStatic());
+					if (this.accessId == 0)
+						this.accessId = scope.enclosingSourceType().roleModel.addInaccessibleBaseMethod(this.binding);
+					this.syntheticAccessor = new SyntheticOTTargetMethod.OTDREMethodDecapsulation(accessor, this.binding.parameters, this.binding.returnType, this.accessId, scope, this);
 				} else {
+					this.binding = new MethodBinding(this.binding, this.binding.declaringClass.getRealClass());
 					this.binding.selector = CharOperation.concat(IOTConstants.OT_DECAPS, this.selector);
 				}
 			}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
index 24a009a..d9e4fd1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
@@ -244,20 +244,24 @@
 								 this.typeArguments = new TypeReference[len], 0, len); // FIXME(SH): reducing this array conflicts with loop condition
 	
 				// note: handling of arrays differs for role and regular types
-				if (len == 0)
+				if (len == 0) {
+					resolveAnnotations(scope, location);
+					if (checkBounds)
+						checkNullConstraints(scope, this.typeArguments);
 					return this.resolvedType; // we're done
+				}
 
 				// proceed with a word of warning:
 				scope.problemReporter().experimentalFeature(this, "Implementation for mixed type and value parameters is experimental.");
 		    }
 		}
 		// find a base import scope if that's allowed:
-	    Scope importScope = null;
+	    CompilationUnitScope importScope = null;
 		if (getBaseclassDecapsulation().isAllowed()) {
 			Scope currentScope = scope;
 			while (currentScope != null) {
 				if (currentScope instanceof OTClassScope) {
-					importScope = ((OTClassScope)currentScope).getBaseImportScope();
+					importScope = ((OTClassScope)currentScope).getBaseImportScope(scope);
 					if (importScope != null)
 						break;
 				}
@@ -268,6 +272,8 @@
 /* orig:
 		TypeBinding type = internalResolveLeafType(scope, enclosingType, checkBounds);
   :giro */
+		if (importScope != null)
+			importScope.originalScope = null;
 // SH}
 
 		// handle three different outcomes:
@@ -553,11 +559,15 @@
 			Scope currentScope = scope;
 			while (currentScope != null) {
 				if (currentScope instanceof OTClassScope) {
-					Scope baseImportScope = ((OTClassScope)currentScope).getBaseImportScope();
+					CompilationUnitScope baseImportScope = ((OTClassScope)currentScope).getBaseImportScope(scope);
 					if (baseImportScope != null) {
-						this.resolvedType = getTypeBinding(baseImportScope);
-						if (this.resolvedType != null && this.resolvedType.isValidBinding())
-							return this.resolvedType = checkResolvedType(this.resolvedType, baseImportScope, location, false);
+						try {
+							this.resolvedType = getTypeBinding(baseImportScope);
+							if (this.resolvedType != null && this.resolvedType.isValidBinding())
+								return this.resolvedType = checkResolvedType(this.resolvedType, baseImportScope, location, false);
+						} finally {
+							baseImportScope.originalScope = null;
+						}
 					}
 				}
 				currentScope = currentScope.parent;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
index c2e277c..b02a358 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
@@ -34,6 +34,7 @@
 import org.eclipse.jdt.internal.compiler.flow.FlowContext;
 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions.WeavingScheme;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
@@ -59,9 +60,11 @@
 import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec.ImplementationStrategy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticOTTargetMethod;
 import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementor;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.FieldModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
@@ -854,7 +857,7 @@
 					// realize decapsulation by simulating an inferred callout-to-field
 					field = closestField;
 					scope.problemReporter().decapsulation(this, field, scope);
-					accessAsCalloutToField(enclosingReceiver, field, index);
+					accessAsCalloutToField(scope, enclosingReceiver, field, index, scope.compilerOptions().weavingScheme);
 					fixedByDecapsulation = true;
 				}
 		  }
@@ -924,19 +927,23 @@
 }
 
 //{ObjectTeams: replace this field reference with an accessor call (simulated as callout-to-field):
-private void accessAsCalloutToField(ReferenceBinding enclosingReceiver, FieldBinding baseclassField, int idx)
+private void accessAsCalloutToField(BlockScope scope, ReferenceBinding enclosingReceiver, FieldBinding baseclassField, int idx, WeavingScheme weaving)
 {
 	ReferenceBinding baseClass = baseclassField.declaringClass;
 
 	// manually create and add binding as if it were a callout to field:
-	final MethodBinding fakedAccessorBinding = FieldModel.getDecapsulatingFieldAccessor(baseClass, baseclassField, true);
-	baseClass.addMethod(fakedAccessorBinding);
+	ImplementationStrategy strategy = weaving == WeavingScheme.OTDRE ? ImplementationStrategy.DYN_ACCESS : ImplementationStrategy.DECAPS_WRAPPER;
+	final MethodBinding fakedAccessorBinding = FieldModel.getDecapsulatingFieldAccessor(scope, baseClass, baseclassField, true, strategy);
 
 	// record the need to have the OTRE create the accessor:
-	enclosingReceiver.roleModel.addAccessedBaseField(baseclassField, TerminalTokens.TokenNameget);
+	int accessid = enclosingReceiver.roleModel.addAccessedBaseField(baseclassField, TerminalTokens.TokenNameget);
 
+	SyntheticMethodBinding accessor = (strategy == ImplementationStrategy.DYN_ACCESS)
+			? new SyntheticOTTargetMethod.OTDREFieldDecapsulation(fakedAccessorBinding, baseclassField.type, accessid, 0/*get*/, scope, this)
+			: new SyntheticOTTargetMethod.CalloutToField(fakedAccessorBinding);
+	
 	// convert to a synthetic method that generateCode can use:
-	setSyntheticAccessor(baseclassField, idx, new SyntheticMethodBinding(fakedAccessorBinding, SyntheticMethodBinding.InferredCalloutToField));
+	setSyntheticAccessor(baseclassField, idx, accessor);
 }
 // SH}
 
@@ -1304,8 +1311,7 @@
 	if (callout != null) {
 		if (this.syntheticReadAccessors == null)
 			this.syntheticReadAccessors = new SyntheticMethodBinding[this.tokens.length];
-		this.syntheticReadAccessors[0] =
-				new SyntheticMethodBinding(callout.roleMethodSpec.resolvedMethod, SyntheticMethodBinding.InferredCalloutToField);
+		this.syntheticReadAccessors[0] = new SyntheticOTTargetMethod.CalloutToField(callout.roleMethodSpec.resolvedMethod);
 		FieldBinding baseField = ((FieldAccessSpec)callout.baseMethodSpec).resolvedField;
 		// update resolved information:
 		this.binding = baseField;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
index f20c7f1..bce8fbf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
@@ -54,6 +54,7 @@
 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticOTTargetMethod;
 import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementor;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.util.RoleTypeCreator;
@@ -1089,7 +1090,7 @@
 		if (this.syntheticAccessors == null)
 			this.syntheticAccessors = new MethodBinding[2];
 		this.syntheticAccessors[isSetter ? FieldReference.WRITE : FieldReference.READ] =
-				new SyntheticMethodBinding(callout.roleMethodSpec.resolvedMethod, SyntheticMethodBinding.InferredCalloutToField);
+						new SyntheticOTTargetMethod.CalloutToField(callout.roleMethodSpec.resolvedMethod);
 		FieldBinding baseField = ((FieldAccessSpec)callout.baseMethodSpec).resolvedField;
 		// update resolved information:
 		this.binding = baseField;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
index 658bc0f..7ee4c81 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
@@ -137,11 +137,15 @@
 			Scope currentScope = scope;
 			while (currentScope != null) {
 				if (currentScope instanceof OTClassScope) {
-					Scope baseImportScope = ((OTClassScope)currentScope).getBaseImportScope();
+					CompilationUnitScope baseImportScope = ((OTClassScope)currentScope).getBaseImportScope(scope);
 					if (baseImportScope != null) {
-						this.resolvedType = getTypeBinding(baseImportScope);
-						if (this.resolvedType != null && this.resolvedType.isValidBinding())
-							return this.resolvedType = checkResolvedType(this.resolvedType, baseImportScope, location, false);
+						try {
+							this.resolvedType = getTypeBinding(baseImportScope);
+							if (this.resolvedType != null && this.resolvedType.isValidBinding())
+								return this.resolvedType = checkResolvedType(this.resolvedType, baseImportScope, location, false);
+						} finally {
+							baseImportScope.originalScope = null;
+						}
 					}
 				}
 				currentScope = currentScope.parent;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
index a065983..c99094a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
@@ -60,6 +60,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticOTMethodBinding;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticOTTargetMethod;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticRoleFieldAccess;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.WeakenedTypeBinding;
 
@@ -4420,16 +4421,17 @@
 	if ((declaringClass.tagBits & TagBits.ContainsNestedTypeReferences) != 0) {
 		Util.recordNestedType(this.classFile, declaringClass);
 	}
-//{ObjectTeams: invoking role field accessors works differently:
+//{ObjectTeams: some OT accessor methods require different codegen:
     if (opcode == Opcodes.OPC_invokestatic) {
-        if (methodBinding instanceof SyntheticRoleFieldAccess) {
-            // these have generation built in:
-            ((SyntheticRoleFieldAccess)methodBinding).generateInvoke(this);
-            return;
-        }
-        // roles as parameter for field access may need casting:
-        if (methodBinding instanceof SyntheticMethodBinding)
-            opcode = checkInvokeCalloutToField(opcode, methodBinding);
+        if (methodBinding instanceof SyntheticOTTargetMethod) {
+        	// these have generation built in:
+			opcode = ((SyntheticOTTargetMethod)methodBinding).prepareOrGenerateInvocation(this, opcode);
+		} else if (methodBinding instanceof SyntheticMethodBinding) {
+			// roles as parameter for field access may need casting:
+			opcode = checkInvokeCalloutToField(opcode, (SyntheticMethodBinding)methodBinding);
+		}
+        if (opcode == 0)
+        	return;
     }
 // SH}
 	// compute receiverAndArgsSize
@@ -4515,38 +4517,31 @@
 // SH}
 }
 //{ObjectTeams: misguided callout-to-field accessor?? 
-private byte checkInvokeCalloutToField(byte opcode, MethodBinding methodBinding) {
-	if (   !methodBinding.isStatic()
-	    && ((SyntheticMethodBinding)methodBinding).purpose == SyntheticMethodBinding.InferredCalloutToField)
+private byte checkInvokeCalloutToField(byte opcode, SyntheticMethodBinding accessor) {
+	if (  (   accessor.purpose == SyntheticMethodBinding.FieldReadAccess
+		   || accessor.purpose == SyntheticMethodBinding.FieldWriteAccess)
+		&& accessor.parameters.length > 0 // for static fields we have no parameter.
+	    && accessor.parameters[0].isRole())
 	{
-		opcode = Opcodes.OPC_invokevirtual;
-	} else {
-		SyntheticMethodBinding accessor = (SyntheticMethodBinding)methodBinding;
-		if (  (   accessor.purpose == SyntheticMethodBinding.FieldReadAccess
-			   || accessor.purpose == SyntheticMethodBinding.FieldWriteAccess)
-			&& accessor.parameters.length > 0 // for static fields we have no parameter.
-		    && accessor.parameters[0].isRole())
-		{
-			boolean wide = false;
-			if (accessor.purpose == SyntheticMethodBinding.FieldWriteAccess) {
-				wide =    accessor.targetWriteField.type.id == TypeIds.T_long
-				       || accessor.targetWriteField.type.id == TypeIds.T_double;
-				// expose first arg of two (role, value)
-				if (wide) {
-					dup2_x1(); // ref, wide -> wide, ref, wide
-					pop2();    //           -> wide, ref
-				} else
-					this.swap();
-			}
-			this.checkcast(methodBinding.parameters[0]);
-			if (accessor.purpose == SyntheticMethodBinding.FieldWriteAccess) {
-				// revert the above swap:
-				if (wide) {
-					dup_x2(); // wide, ref -> ref, wide, ref
-					pop();    //           -> ref, wide
-				} else
-					this.swap();
-			}
+		boolean wide = false;
+		if (accessor.purpose == SyntheticMethodBinding.FieldWriteAccess) {
+			wide =    accessor.targetWriteField.type.id == TypeIds.T_long
+			       || accessor.targetWriteField.type.id == TypeIds.T_double;
+			// expose first arg of two (role, value)
+			if (wide) {
+				dup2_x1(); // ref, wide -> wide, ref, wide
+				pop2();    //           -> wide, ref
+			} else
+				this.swap();
+		}
+		this.checkcast(accessor.parameters[0]);
+		if (accessor.purpose == SyntheticMethodBinding.FieldWriteAccess) {
+			// revert the above swap:
+			if (wide) {
+				dup_x2(); // wide, ref -> ref, wide, ref
+				pop();    //           -> ref, wide
+			} else
+				this.swap();
 		}
 	}
 	return opcode;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
index 0c2295e..2880794 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
@@ -91,6 +91,9 @@
 	private boolean skipCachingImports;
 
 	boolean connectingHierarchy;
+//{ObjectTeams: when used as a baseimport scope, remember the original scope during this current lookup
+	public Scope originalScope;
+// SH}
 
 public CompilationUnitScope(CompilationUnitDeclaration unit, LookupEnvironment environment) {
 	super(COMPILATION_UNIT_SCOPE, null);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index eeb4bb2..9105cb7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -5660,6 +5660,13 @@
 			case Scope.METHOD_SCOPE :
 				resolutionScope = (BlockScope) scope;
 				break;
+//{ObjectTeams: consider baseImportScopes:
+			case Scope.COMPILATION_UNIT_SCOPE:
+				Scope originalScope = ((CompilationUnitScope)scope).originalScope;
+				if (originalScope instanceof BlockScope)
+					return (BlockScope) originalScope;
+				break;
+// SH}
 		}
 		return resolutionScope;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
index 9623091..2133ad4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -66,6 +66,7 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions.WeavingScheme;
 import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
@@ -77,6 +78,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.RoleFileCache;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TypeAnchorReference;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TypeValueParameter;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec.ImplementationStrategy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.control.*;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.AnchorMapping;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticBaseCallSurrogate;
@@ -2351,12 +2353,16 @@
 			ReferenceBinding originalRole = field.declaringClass;
 			if (field.copyInheritanceSrc != null)
 				originalRole = field.copyInheritanceSrc.declaringClass;
-			inner = FieldModel.getDecapsulatingFieldAccessor(this, field, true/*isGetter*/);
-			((SourceTypeBinding) enclosingType()).addSyntheticRoleMethodBridge(this, originalRole, inner, SyntheticMethodBinding.RoleMethodBridgeOuter);
-			if (!field.isFinal()) { // no setter for final (includes all static role fields)
-								    // otherwise we would have to handle different signatures (w/ w/o role arg), which we currently don't
-				inner = FieldModel.getDecapsulatingFieldAccessor(this, field, false/*isGetter*/);
+			ImplementationStrategy strategy = this.scope.compilerOptions().weavingScheme == WeavingScheme.OTDRE
+												? ImplementationStrategy.DYN_ACCESS : ImplementationStrategy.DECAPS_WRAPPER;
+			if (strategy != ImplementationStrategy.DYN_ACCESS) {
+				inner = FieldModel.getDecapsulatingFieldAccessor(this.scope, this, field, true/*isGetter*/, strategy);
 				((SourceTypeBinding) enclosingType()).addSyntheticRoleMethodBridge(this, originalRole, inner, SyntheticMethodBinding.RoleMethodBridgeOuter);
+				if (!field.isFinal()) { // no setter for final (includes all static role fields)
+									    // otherwise we would have to handle different signatures (w/ w/o role arg), which we currently don't
+					inner = FieldModel.getDecapsulatingFieldAccessor(this.scope, this, field, false/*isGetter*/, strategy);
+					((SourceTypeBinding) enclosingType()).addSyntheticRoleMethodBridge(this, originalRole, inner, SyntheticMethodBinding.RoleMethodBridgeOuter);
+				}
 			}
 		}
 // SH}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
index f3afea9..73a188d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
@@ -69,6 +69,7 @@
 	public final static int InferredCalloutToField = 18; // calling an inferred callout-to-field
 	public final static int RoleMethodBridgeOuter = 19; // a team-level bridge method towards a private role method (for callout)
 	public final static int RoleMethodBridgeInner = 20; // a role-level bridge method towards a private role method (for callout)
+	public final static int MethodDecapsulation = 21;
 // SH}
 
 	public int sourceStart = 0; // start position of the matching declaration
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
index 177da4b..b62c2d4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
@@ -3123,9 +3123,13 @@
 	optimizedConcatNodeLists();
 }
 protected void consumeCatchFormalParameter() {
+//{ObjectTeams: support LiftingTypeReference:
+// orig:
+// CatchFormalParameter ::= Modifiersopt CatchType VariableDeclaratorId
+// :giro
 	// CatchFormalParameter ::= Modifiersopt CatchType CatchLiftingTypeopt VariableDeclaratorId
 	// CatchLiftingType ::= 'as' Type
-
+// SH}
 	this.identifierLengthPtr--;
 	char[] identifierName = this.identifierStack[this.identifierPtr];
 	long namePositions = this.identifierPositionStack[this.identifierPtr--];
@@ -6671,20 +6675,6 @@
 }
 protected void consumeOneMoreTypeAnnotation() {
 	// TypeAnnotations ::= TypeAnnotations TypeAnnotation
-//{ObjectTeams: inside a sentinel-delimited list?
-	if (this.typeAnnotationLengthPtr > 1) {
-		int l = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr-2];
-		if (this.typeAnnotationPtr - l - 1 > -1) {
-			if (this.typeAnnotationStack[this.typeAnnotationPtr - l - 1] == annotationSentinel) {
-				// so we have a sentinal delimited list of annotations at lenghts[-2]
-				// merge into that list rather than in into the list at [-1]
-				this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr-2]++;
-				this.typeAnnotationLengthStack[--this.typeAnnotationLengthPtr] = 0;
-				return;
-			}
-		}
-	}
-// SH}
 	this.typeAnnotationLengthStack[--this.typeAnnotationLengthPtr]++;
 }
 protected void consumeNameArrayType() {
@@ -7602,6 +7592,11 @@
 	// PushZeroTypeAnnotations ::= $empty
 	// Name ::= SimpleName
 	// TypeAnnotationsopt ::= $empty
+//{ObjectTeams: check presence of annotation sentinel (no longer needed, ambiguous tokens will be interpreted as type annotation):
+	if (confirmTypeAnnotation()) {
+		return;
+	}
+// SH}
 	pushOnTypeAnnotationLengthStack(0); // signal absence of @308 annotations.
 }
 // This method is part of an automatic generation : do NOT edit-modify
@@ -7687,6 +7682,10 @@
 		    consumeZeroTypeAnnotations();  
 			break;
  
+    case 85 : if (DEBUG) { System.out.println("TypeAnnotationsopt -> TypeAnnotations"); }  //$NON-NLS-1$
+		    confirmTypeAnnotation();  
+			break;
+ 
      case 88 : if (DEBUG) { System.out.println("TypeAnnotations0 ::= TypeAnnotations0 TypeAnnotation"); }  //$NON-NLS-1$
 		    consumeOneMoreTypeAnnotation();  
 			break;
@@ -9390,6 +9389,10 @@
 		    consumeTypeArgument();  
 			break;
  
+    case 760 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument -> AnyTypeAnchor"); }  //$NON-NLS-1$
+		    confirmTypeAnchor();  
+			break;
+ 
     case 761 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument ::=..."); }  //$NON-NLS-1$
 		    consumeTypeArgumentFromAnchor();  
 			break;
@@ -9398,6 +9401,10 @@
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
  
+    case 763 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument1 ::= AnyTypeAnchor..."); }  //$NON-NLS-1$
+		    confirmTypeAnchor();  
+			break;
+ 
     case 764 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument1 ::=..."); }  //$NON-NLS-1$
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
@@ -9406,6 +9413,10 @@
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
  
+    case 766 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument2 ::= AnyTypeAnchor..."); }  //$NON-NLS-1$
+		    confirmTypeAnchor();  
+			break;
+ 
     case 767 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument2 ::=..."); }  //$NON-NLS-1$
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
@@ -9414,6 +9425,10 @@
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
  
+    case 769 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument3 ::= AnyTypeAnchor..."); }  //$NON-NLS-1$
+		    confirmTypeAnchor();  
+			break;
+ 
     case 770 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument3 ::=..."); }  //$NON-NLS-1$
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
@@ -11406,6 +11421,9 @@
 }
 // SH}
 //{ObjectTeams: new syntax for dependent types.
+
+//==== handle situations of TentativeTypeAnchor: could be either a TypeAnchor or a TypeAnnotation ====
+
 protected void consumeTypeAnchor(boolean haveBase) {
 	// TentativeTypeAnchor ::= '@OT' UnannotatableName
 	// TypeAnchor ::= '@OT' 'base'
@@ -11413,6 +11431,8 @@
 
 	// see also skipThisAnchor() and consumeQualifiedBaseTypeAnchor() for related productions
 	
+	// could be either TypeAnchor or TypeAnnotation
+	// create TypeAnchor for now, two avoid awaiting the decision between Annotation w or w/o member values
 	NameReference anchor = haveBase ?
 		  newBaseReference()
 		: getUnspecifiedReference(false);
@@ -11420,9 +11440,11 @@
 	// anchor has no type annotations, yet it will be consumed in a context where type annotations are possible
 	pushOnTypeAnnotationLengthStack(0);
 }
+
 // this sentinel annotation is pushed below a type annotation that was converted from a type anchor.
 // it signals to a subsequent type annotation that it shall be merged into the existing list
 static final Annotation annotationSentinel = new MarkerAnnotation(new SingleTypeReference("annotationSentinel".toCharArray(), 0), 0); //$NON-NLS-1$
+
 protected void convertTypeAnchor(int annotationKind) {
 	// rule number corresponds to argument annotationKind:
 	// (0) NotAnAnchor ::= $empty
@@ -11482,6 +11504,7 @@
 	}
 	// and push it back
 	this.typeAnnotationLengthPtr--; // drop the empty list pushed in consumeTypeAnchor()
+	// mark that the following annotation may have to be integrated into a subsequent type annotation list:
 	pushOnTypeAnnotationStack(annotationSentinel);
 	pushOnTypeAnnotationStack(annotation);
 	// still need to check if the type annotation is legal:
@@ -11491,23 +11514,51 @@
 		problemReporter().invalidUsageOfTypeAnnotations(annotation);
 	}
 }
-protected void consumeTypeArgumentFromAnchor() {
-	// TypeAnchorOrAnnotatedTypeArgument -> TentativeTypeAnchor NotAnAnchor ReferenceType
 
-	// the Name in ReferenceType has pushed an annotation length,
-	// merge that into the previous empty list (from convertTypeAnchor()):
-	int dim = this.intStack[this.intPtr];
-	int ptr = this.typeAnnotationLengthPtr;
-	if (dim > 1) {
-		this.typeAnnotationLengthStack[ptr-dim] += this.typeAnnotationLengthStack[ptr-dim+1];
-		System.arraycopy(this.typeAnnotationLengthStack, ptr-dim+2, this.typeAnnotationLengthStack, ptr-dim+1, dim-1);
-	} else {
-		this.typeAnnotationLengthStack[ptr-1] += this.typeAnnotationLengthStack[ptr];		
-	}
+// --- The following two methods terminate a sentinal situation, by confirming either a type anchor or a type annotation list: ---
+protected void confirmTypeAnchor() {
+	// TypeAnchorOrAnnotatedTypeArgument -> AnyTypeAnchor
+	// TypeAnchorOrAnnotatedTypeArgument1 -> AnyTypeAnchor '>'
+	// TypeAnchorOrAnnotatedTypeArgument2 -> AnyTypeAnchor '>>'
+	// TypeAnchorOrAnnotatedTypeArgument3 -> AnyTypeAnchor '>>>'
+	
+	// tentative type anchor is indeed a type anchor (not converted to type annotation).
+	// need to remove the empty type annotation list now (see consumeTypeAnchor()).
 	this.typeAnnotationLengthPtr--;
-	// collect everything into a regular type argument:
+}
+protected boolean confirmTypeAnnotation() {
+	// TypeAnnotationsopt ::= $empty
+	// /.$putCase consumeZeroTypeAnnotations(); $break ./
+	//   - internally calls confirmTypeAnnotation()
+	// TypeAnnotationsopt -> TypeAnnotations
+	
+	int sentinelPos = -1;
+	if (this.typeAnnotationLengthPtr != -1) {
+		int len = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr];
+		sentinelPos = this.typeAnnotationPtr - len;
+		if (sentinelPos > -1 && this.typeAnnotationStack[sentinelPos] == annotationSentinel) {
+			// new (possibly zero) Type Annotation in a sentinal situation means: the sentinel has served its purpose, we move on.
+			// Ergo:
+			// - remove the sentinel, transforming the special list into a regular one (lenght is already correct).
+			// - this leaves the rest of the sentinel list as the pending type annotations (instead of zero)
+			System.arraycopy(this.typeAnnotationStack, sentinelPos+1, this.typeAnnotationStack, sentinelPos, len);
+			this.typeAnnotationPtr--;
+			return true; // yes, we were in a sentinel situation
+		}
+	}
+	return false; // no, nothing ambiuous to confirm
+}
+//--- finally collect the pieces involving the TentativeTypeAnchor that was not an anchor:
+protected void consumeTypeArgumentFromAnchor() {
+	// TypeAnchorOrAnnotatedTypeArgument ::= TentativeTypeAnchor NotAnAnchor ReferenceType
+
+	// original rule:
+	// TypeArgument ::= ReferenceType
+	// /.$putCase consumeTypeArgument(); $break ./
+
 	consumeTypeArgument();
-	this.typeAnnotationPtr--; // drop the annotationSentinel
+	if (this.typeAnnotationPtr > -1 && this.typeAnnotationStack[this.typeAnnotationPtr] == annotationSentinel)
+		this.typeAnnotationPtr--; // drop the annotationSentinel if still present
 }
 protected void consumeAnnotationsOnTypeArgumentFromAnchor() {
 	// TypeAnchorOrAnnotatedTypeArgument -> TentativeTypeAnchor NotAnAnchor Wildcard
@@ -11518,39 +11569,17 @@
 	// TypeAnchorOrAnnotatedTypeArgument2 -> TentativeTypeAnchor NotAnAnchor ReferenceType2
 	// TypeAnchorOrAnnotatedTypeArgument2 -> TentativeTypeAnchor NotAnAnchor Wildcard2
 
-	// in all these cases a type reference (with dims) already exists
-	// and only type annotations need to be added/merged (if any)
-	
-	TypeReference ref = (TypeReference) this.genericsStack[this.genericsPtr];
-	// insert or merge converted annotation at first level into ref's annotations:
-	int length = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr--];
-	if (length != 0) {
-		if (ref.annotations == null)
-			ref.annotations = new Annotation[ref.getAnnotatableLevels()][];
-		Annotation[] annotations = ref.annotations[0];
-		int oldLen = 0;
-		if (annotations != null) {
-			oldLen = annotations.length;
-			System.arraycopy(annotations, 0, annotations = new Annotation[oldLen+length], length, oldLen);
-		} else {
-			annotations = new Annotation[length];				
-		}
-		System.arraycopy(
-				this.typeAnnotationStack,
-				(this.typeAnnotationPtr -= length) + 1,
-				annotations,
-				0,
-				length);
-		ref.annotations[0] = annotations;
-		ref.sourceStart = annotations[0].sourceStart;
-		ref.bits |= ASTNode.HasTypeAnnotations;
-	}
-	// type references are already on genericsStack, will be collected by consumeTypeArgumentList1()
-	this.typeAnnotationPtr--; // drop the annotationSentinel
+	// in all these cases a type reference (with dims) already exists on the genericsStack
+	//    (will be collected by consumeTypeArgumentList1())
+	// type annotations should have been attached via the tail of the production (e.g., consumeReferenceType1())
+
+	// now just perform final clean-up:
+	if (this.typeAnnotationPtr > -1 && this.typeAnnotationStack[this.typeAnnotationPtr] == annotationSentinel)
+		this.typeAnnotationPtr--; // drop the annotationSentinel if still present
 }
-protected NameReference newBaseReference() {
-	return new SingleNameReference(IOTConstants._OT_BASE, (((long)this.intStack[this.intPtr--])<<32)+this.intStack[this.intPtr--]);
-}
+
+// ==============================================
+
 protected void skipThisAnchor() {
 	// TypeAnchor ::= '@OT' 'this'
 	//   where '@OT' is the synthetic token returned by the parser when a '@' is in a position suitable for a type anchor
@@ -11558,6 +11587,8 @@
 	// Cannot use ThisReference as type anchor.
 	// Since R<@this> is redundant, simply drop the argument (see also concatGenericsList()).
 	this.intPtr-=2;
+	// anchor has not type annotations, yet it will be consumed in a context where type annotations are possible
+	pushOnTypeAnnotationLengthStack(0);
 }
 protected void consumeQualifiedBaseTypeAnchor() {
 	// TypeAnchor ::= '@OT' UnannotatableName '.' 'base'
@@ -11566,7 +11597,8 @@
 	// handle type arguments (see consumePrimaryNoNewArrayNameThis):
 	pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
 	pushOnGenericsLengthStack(0); // handle type arguments
-	TypeReference prefix = getTypeReference(0);
+	pushOnTypeAnnotationLengthStack(0); // unannotated by construction, but haven't yet pushed zero type annotatations
+	TypeReference prefix = getTypeReference(0); // consumes the above zero type annotations
 	
 	Reference anchor = new QualifiedBaseReference(prefix, this.intStack[this.intPtr--], this.intStack[this.intPtr--]);
 	pushOnGenericsStack(new TypeAnchorReference(anchor, this.intStack[this.intPtr--]));
@@ -11605,6 +11637,10 @@
 	TypeParameter parameter = (TypeParameter) this.genericsStack[this.genericsPtr];
 	parameter.bounds = new TypeReference[] { bound };
 }
+// ----
+protected NameReference newBaseReference() {
+	return new SingleNameReference(IOTConstants._OT_BASE, (((long)this.intStack[this.intPtr--])<<32)+this.intStack[this.intPtr--]);
+}
 // SH}
 protected void consumeTypeArgument() {
 	pushOnGenericsStack(getTypeReference(this.intStack[this.intPtr--]));
@@ -14719,10 +14755,9 @@
 			stackLength);
 	}
 //{ObjectTeams: at the sentinal situation we merge this new annotation into the previous list:
-  if (atSentinel) {
-	this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr-1]++;
-	this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr] = 0; // clear any previous data to start an empty list
-  } else
+  if (atSentinel)
+	this.typeAnnotationLengthStack[--this.typeAnnotationLengthPtr]++;
+  else
 // SH}
 	this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr] = 1;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc
index c8f6027..57d2985 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props
index b198740..fd6a148 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props
@@ -370,9 +370,9 @@
 TryStatementWithResources=TryStatementWithResources
 Type=Type
 TypeAnchor=typeAnchor
-TypeAnchorOrAnnotatedTypeArgument1=TypeArgument
-TypeAnchorOrAnnotatedTypeArgument2=TypeArgument
-TypeAnchorOrAnnotatedTypeArgument3=TypeArgument
+TypeAnchorOrAnnotatedTypeArgument1=TypeAnchor
+TypeAnchorOrAnnotatedTypeArgument2=TypeAnchor
+TypeAnchorOrAnnotatedTypeArgument3=TypeAnchor
 TypeAnchorOrAnnotatedTypeArgument=TypeArgument
 TypeAnnotation=TypeAnnotation
 TypeAnnotationName=AnnotationName
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java
index 7a94687..513bc7a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java
@@ -1,7 +1,7 @@
 /**********************************************************************
  * This file is part of "Object Teams Development Tooling"-Software
  *
- * Copyright 2004, 2011 Fraunhofer Gesellschaft, Munich, Germany,
+ * Copyright 2004, 2014 Fraunhofer Gesellschaft, Munich, Germany,
  * for its Fraunhofer Institute for Computer Architecture and Software
  * Technology (FIRST), Berlin, Germany and Technical University Berlin,
  * Germany.
@@ -185,8 +185,7 @@
 				targetClass = roleModel.getBaseTypeBinding();	// use the specific declared bound class (avoids weaving into possibly inaccessible super base)
 
 			// create accessor method:
-			result = createMethod(targetClass, accessorSelector);
-			baseType.addMethod(result);
+			result = createMethod(scope, targetClass, accessorSelector);
 		}
 		this.selector = accessorSelector;
 		this.resolvedMethod = result;
@@ -220,7 +219,7 @@
 	/**
 	 *  Create a faked method binding representing the access method to be generated by OTRE.
 	 */
-	private MethodBinding createMethod(ReferenceBinding baseType, char[] accessorSelector) {
+	private MethodBinding createMethod(Scope scope, ReferenceBinding baseType, char[] accessorSelector) {
 		if (baseType.isRoleType())
 			baseType = baseType.getRealClass();
     	if (this.calloutModifier == TerminalTokens.TokenNameget) {
@@ -228,21 +227,31 @@
     		// because several callouts to the same field could exist.
     		// RoleTypeCreator.maybeWrapQualifiedRoleType(MessageSend,BlockScope)
     		// will wrap the type using a faked _OT$base receiver.
-    		return FieldModel.getDecapsulatingFieldAccessor(baseType, this.resolvedField, true);
+    		return FieldModel.getDecapsulatingFieldAccessor(scope, baseType, this.resolvedField, true, this.implementationStrategy);
 		} else {
     		TypeBinding declaredFieldType = this.hasSignature ?
 					this.parameters[0] :
 					this.fieldType;
-    		TypeBinding[] argTypes = this.resolvedField.isStatic() ?
+			int access;
+			TypeBinding[] argTypes;
+			if (this.implementationStrategy == ImplementationStrategy.DYN_ACCESS) {
+				access = ClassFileConstants.AccPublic;
+				argTypes = new TypeBinding[]{declaredFieldType};
+			} else {
+				access = ClassFileConstants.AccPublic|ClassFileConstants.AccStatic;
+				argTypes = this.resolvedField.isStatic() ?
     									new TypeBinding[]{declaredFieldType} :
     									new TypeBinding[]{baseType, declaredFieldType};
-			return new MethodBinding(
-    				ClassFileConstants.AccPublic|ClassFileConstants.AccStatic,
+			}
+			MethodBinding result = new MethodBinding(
+    					access,
 						accessorSelector,
 						TypeBinding.VOID,
 						argTypes,
 						Binding.NO_EXCEPTIONS,
 						baseType);
+			baseType.addMethod(result);
+			return result;
     	}
 	}
 
@@ -265,10 +274,10 @@
      */
     public TypeBinding[] resolvedParameters() {
     	if (this.resolvedMethod == null)
-    		return this.parameters; // empty; FIXME(SH): handle "set" access
+    		return this.parameters;
     	TypeBinding[] methodParams = super.resolvedParameters();
-    	if (this.resolvedField.isStatic())
-    		return methodParams; // no base argument when accessing a static field
+    	if (this.resolvedField.isStatic() || this.implementationStrategy == ImplementationStrategy.DYN_ACCESS)
+    		return methodParams; // no base argument when accessing a static field, or in OTDRE mode
 		TypeBinding[] result = new TypeBinding[methodParams.length-1];
     	System.arraycopy(methodParams, 1, result, 0, result.length);
     	return result;
@@ -329,7 +338,7 @@
 		if (this.calloutModifier == TerminalTokens.TokenNameget)
 			return true; // no parameter
 		int argumentPosition = 0; // safer against AIOOBE
-		if (this.resolvedField != null && !this.resolvedField.isStatic())
+		if (this.resolvedField != null && !this.resolvedField.isStatic() && this.implementationStrategy != ImplementationStrategy.DYN_ACCESS)
 			argumentPosition = 1;
 		TypeBinding accessorParamType = null;
 		if (this.resolvedMethod != null)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java
index c5bb210..1f43e7d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java
@@ -38,9 +38,9 @@
 import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.LongLiteral;
+import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
 import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
-import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
 import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding;
@@ -206,7 +206,7 @@
 	    			ITeamAnchor anchor = null;
 	    			if (roleRefType.baseclass() instanceof RoleTypeBinding)
 	    				anchor = ((RoleTypeBinding)roleRefType.baseclass())._teamAnchor;
-	    			roleBase = parameterizedRole.environment.createParameterizedType((ReferenceBinding)roleBase.original(), typeArgs, anchor, -1, roleBase.enclosingType(), Binding.NO_ANNOTATIONS);
+	    			roleBase = parameterizedRole.environment.createParameterizedType((ReferenceBinding)roleBase.original(), typeArgs, anchor, -1, roleBase.enclosingType(), roleBase.getTypeAnnotations());
 	    		}
 	    		// THE compatibility check:
 		    	if (   !baseType.isCompatibleWith(roleBase)
@@ -260,6 +260,17 @@
 	    return null;
 	}
 
+	public void updateBindingAndCheckNullness(BlockScope scope) {
+		this.baseReference.resolvedType = this.resolvedType;
+		TypeBinding roleType = this.roleReference.resolvedType;
+		if (roleType != null && roleType.isValidBinding() && scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) {
+	    	NullAnnotationMatching status = NullAnnotationMatching.analyse(roleType, this.resolvedType, -1);
+			if (status.isAnyMismatch()) {
+	    		scope.problemReporter().nullityMismatchingTypeAnnotation(this.fakedArgument.initialization, this.resolvedType, roleType, status);
+	    	}
+		}
+	}
+
 	@Override
 	public char [][] getTypeName() {
 		return this.baseTokens;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java
index a758b2e..d241b00 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java
@@ -45,6 +45,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.ConstantPoolObjectReader.IncompatibleBytecodeException;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.ArrayTranslations;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.Lifting;
+import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementorDyn;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
@@ -161,6 +162,10 @@
         	dstMethod.binding.bytecodeMissing= true;
        		return;
         }
+        
+		if (CharOperation.equals(CalloutImplementorDyn.OT_ACCESS, dstMethod.selector)
+			||CharOperation.equals(CalloutImplementorDyn.OT_ACCESS_STATIC, dstMethod.selector))
+        	return;
 
         byte[] srcConstantPool  = null;
         int    offset           = -1;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/ConstantPoolObjectReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/ConstantPoolObjectReader.java
index e652076..39a6940 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/ConstantPoolObjectReader.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/ConstantPoolObjectReader.java
@@ -55,6 +55,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticBaseCallSurrogate;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticRoleFieldAccess;
 import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CallinImplementorDyn;
+import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementorDyn;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.TypeModel;
@@ -487,7 +488,9 @@
 	boolean isSynthMethodName(char[] name) {
 		return 
 			CharOperation.prefixEquals(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, name)
-			|| CharOperation.prefixEquals(TypeConstants.SYNTHETIC_SWITCH_ENUM_TABLE, name);
+			|| CharOperation.prefixEquals(TypeConstants.SYNTHETIC_SWITCH_ENUM_TABLE, name)
+			|| CharOperation.equals(CalloutImplementorDyn.OT_ACCESS, name)
+			|| CharOperation.equals(CalloutImplementorDyn.OT_ACCESS_STATIC, name);
 	}
 
 	/** Detect methods that will be generated by the OTRE. If match return the assumed modifiers */
@@ -507,6 +510,10 @@
 			return AccPublic;
 		if (CharOperation.equals(CallinImplementorDyn.OT_CALL_BEFORE, name))
 			return AccPublic;
+		if (CharOperation.equals(CalloutImplementorDyn.OT_ACCESS, name))
+			return AccPublic;
+		if (CharOperation.equals(CalloutImplementorDyn.OT_ACCESS_STATIC, name))
+			return AccPublic;
 		return 0;
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/DeclaredLifting.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/DeclaredLifting.java
index afd177b..0e9ff76 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/DeclaredLifting.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/DeclaredLifting.java
@@ -45,6 +45,7 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
 import org.eclipse.jdt.internal.compiler.lookup.MemberTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
@@ -244,9 +245,11 @@
 					ReferenceBinding baseType = null;
 					if (scope.classScope() instanceof OTClassScope) {
 						// try base scope first:
-						Scope baseScope = ((OTClassScope) scope.classScope()).getBaseImportScope();
-						if (baseScope != null)
+						CompilationUnitScope baseScope = ((OTClassScope) scope.classScope()).getBaseImportScope(scope);
+						if (baseScope != null) {
 							baseType = (ReferenceBinding) baseScope.getType(ltr.baseTokens, ltr.baseTokens.length);
+							baseScope.originalScope = null;
+						}
 					} 
 					if (baseType == null || !baseType.isValidBinding())
 						// fall back to normal scope:
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/OTClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/OTClassScope.java
index b990fd4..5c6d287 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/OTClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/OTClassScope.java
@@ -301,7 +301,9 @@
 		this.baseImportScope.topLevelTypes = new SourceTypeBinding[0];
 	}
 
-	public Scope getBaseImportScope() {
+	public CompilationUnitScope getBaseImportScope(Scope originalScope) {
+		if (this.baseImportScope != null)
+			this.baseImportScope.originalScope = originalScope;
 		return this.baseImportScope;
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/RoleTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/RoleTypeBinding.java
index 7289081..c914805 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/RoleTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/RoleTypeBinding.java
@@ -235,6 +235,11 @@
 		// record as known role type at teamAnchor and in our own cache
         registerAnchor();
     }
+    
+    public TypeBinding clone(TypeBinding outerType) {
+    	RoleTypeBinding clone = new RoleTypeBinding(this.type, typeArguments(), this._teamAnchor, (ReferenceBinding) outerType, this.environment);
+    	return clone;
+    }
 
     // hook of maybeInstantiate
     TypeBinding forAnchor(ITeamAnchor anchor, int dimensions) {
@@ -956,20 +961,18 @@
     	return super.attributeName();
     }
     public String toString() {
-    	String anchorStr = ""; //$NON-NLS-1$
+    	StringBuilder sb = new StringBuilder();
+    	sb.append(annotatedDebugName());
+    	sb.append('<').append('@');
     	ITeamAnchor[] bestNamePath = this._teamAnchor.getBestNamePath(false);
 		for (int i = 0; i < bestNamePath.length; i++) {
     		if (i>0)
-    			anchorStr += '.';
-			anchorStr += new String(bestNamePath[i].readableName());
+    			sb.append('.');
+			sb.append(bestNamePath[i].readableName());
 		}
-    	String staticTeam = ""; //$NON-NLS-1$
-    	if (!(this._teamAnchor instanceof TThisBinding))
-    		staticTeam = '['+new String(this._staticallyKnownTeam.sourceName())+']';
-        return
-            anchorStr
-            +staticTeam
-            +'.'
-            +new String(sourceName());
+		if (!(this._teamAnchor instanceof TThisBinding))
+			sb.append('[').append(this._staticallyKnownTeam.sourceName()).append(']');
+		sb.append('>');
+		return sb.toString();
     }
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/SyntheticOTTargetMethod.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/SyntheticOTTargetMethod.java
new file mode 100644
index 0000000..cfbdca8
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/SyntheticOTTargetMethod.java
@@ -0,0 +1,251 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2014 GK Software AG
+ * 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * 	  Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otdt.internal.core.compiler.lookup;
+
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
+import org.eclipse.jdt.internal.compiler.codegen.Opcodes;
+import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+
+/**
+ * A synthetic method binding, which used as an invocation target needs to
+ * influence code generation.
+ * 
+ * @since 2.3.1
+ */
+public abstract class SyntheticOTTargetMethod extends SyntheticMethodBinding {
+
+	protected SyntheticOTTargetMethod(MethodBinding targetMethod, int purpose) {
+		super(targetMethod, purpose);
+	}
+	
+	protected SyntheticOTTargetMethod(FieldBinding targetField, boolean isReadAccess, boolean isSuperAccess, SourceTypeBinding declaringClass) {
+		super(targetField, isReadAccess, isSuperAccess, declaringClass);
+	}
+
+	protected SyntheticOTTargetMethod(BinaryTypeBinding declaringClass, int modifiers, char[] selector,
+			TypeBinding[] parameters, TypeBinding returnType) {
+		super(declaringClass, modifiers, selector, parameters, returnType);
+	}
+
+	/**
+	 * We assume: all arguments of an invocation have already been pushed.
+	 * At this point we may insert additional byte codes, or generate the actual invocation.
+	 * @return 0 means: no further action needed, else we return the opcode for which the actual
+	 * 						invoke still needs to be generated.
+	 */
+	public abstract byte prepareOrGenerateInvocation(CodeStream codeStream, byte opcode);
+	
+	/**
+	 * Represents an inferred callout-to-field.
+	 * May need to tweak invokestatic (for regular access$n methods) into invokevirtual (for the generated c-t-f method).
+	 */
+	public static class CalloutToField extends SyntheticOTTargetMethod {
+		public CalloutToField(MethodBinding targetMethod) {
+			super(targetMethod, InferredCalloutToField);
+		}
+
+		@Override
+		public byte prepareOrGenerateInvocation(CodeStream codeStream, byte opcode) {
+			if (!isStatic() && this.purpose == SyntheticMethodBinding.InferredCalloutToField)
+				return Opcodes.OPC_invokevirtual;
+			return opcode;
+		}
+	}
+	
+	/**
+	 * Represents a decapsulating field access while targeting OTDRE.
+	 * We need to generate a special sequence to call _OT$access(int,int,Object[],ITeam)
+	 * Currently only supports read access.
+	 * Typical use is when a base predicate refers to a private base field.
+	 */
+	public static class OTDREFieldDecapsulation extends SyntheticOTTargetMethod {
+
+		private int accessId;
+		private int opKind;
+		private ReferenceBinding enclosingTeam;
+		private TypeBinding originalType;
+		private ASTNode site;
+		private BlockScope scope;
+		
+		/**
+		 * Create a binding for a field access using decapsulation.
+		 * @param fakedMethod this method is member of the base class, representing the otdre-generated access method.
+		 * @param originalType return type of the original feature (field)
+		 * @param accessId ID by which the base field is identified inside the access method
+		 * @param opKind 0 = get, 1 = set
+		 * @param scope where this access has been seen
+		 * @param site the exact node where decapsulation happened
+		 */
+		public OTDREFieldDecapsulation(MethodBinding fakedMethod, TypeBinding originalType, int accessId, int opKind, BlockScope scope, ASTNode site) {
+			super(fakedMethod, SyntheticMethodBinding.InferredCalloutToField);
+			this.accessId = accessId;
+			this.opKind = opKind;
+			ReferenceBinding enclosingRole = scope.enclosingReceiverType();
+			this.enclosingTeam = enclosingRole.enclosingType();
+			this.originalType = originalType;
+			this.site = site;
+			this.scope = scope;
+		}
+
+		@Override
+		public byte prepareOrGenerateInvocation(CodeStream codeStream, byte opcode) {
+			// accessId
+			codeStream.bipush((byte) this.accessId);
+			// 0 = get, 1 = set
+			if (this.opKind == 0)
+				codeStream.iconst_0();
+			else
+				codeStream.iconst_1();
+			// no args to pack for read access:
+			codeStream.aconst_null(); 
+			// enclosing team instance:
+			Object[] emulationPath = this.scope.getEmulationPath(this.enclosingTeam, true /*only exact match*/, false/*consider enclosing arg*/);
+			codeStream.generateOuterAccess(emulationPath, this.site, this.enclosingTeam, this.scope);
+			// invoke it:
+			byte invoke = this.targetMethod.isStatic() ? Opcodes.OPC_invokestatic : Opcodes.OPC_invokevirtual;
+			codeStream.invoke(invoke, this.targetMethod, this.targetMethod.declaringClass);
+			// convert result?:
+			if (this.originalType != TypeBinding.VOID) {
+				if (this.originalType.isBaseType()) {
+					codeStream.checkcast(this.scope.environment().computeBoxingType(this.originalType));
+					codeStream.generateUnboxingConversion(this.originalType.id);
+				} else {
+					codeStream.checkcast(this.originalType);
+				}
+			} else {
+				// what? - not hit for field read :)
+			}
+			return 0; // signal we're done
+		}
+	}
+
+	/**
+	 * Represents a decapsulating method access while targeting OTDRE (not an explicit callout).
+	 * We need to generate a special sequence to call _OT$access(int,int,Object[],ITeam)
+	 */
+	public static class OTDREMethodDecapsulation extends SyntheticOTTargetMethod {
+
+		private int accessId;
+		private ReferenceBinding enclosingTeam;
+		private TypeBinding[] originalParameters;
+		private TypeBinding originalReturnType;
+		private ASTNode site;
+		private BlockScope scope;
+		
+		/**
+		 * Create a binding for a method access using decapsulation.
+		 * @param targetMethod this method is member of the base class, representing the otdre-generated access method.
+		 * @param originalParameters parameters of the original target method (before replacing with _OT$access)
+		 * @param originalReturn return type of the original target method (before replacing with _OT$access)
+		 * @param accessId ID by which the base field is identified inside the access method
+		 * @param scope where this access has been seen
+		 * @param site the exact node where decapsulation happened
+		 */
+		public OTDREMethodDecapsulation(MethodBinding targetMethod, TypeBinding[] originalParameters, TypeBinding originalReturn, int accessId, BlockScope scope, ASTNode site) {
+			super(targetMethod, SyntheticMethodBinding.MethodDecapsulation);
+			this.accessId = accessId;
+			ReferenceBinding enclosingRole = scope.enclosingReceiverType();
+			this.enclosingTeam = enclosingRole.enclosingType();
+			this.originalParameters = originalParameters;
+			this.originalReturnType = originalReturn;
+			this.site = site;
+			this.scope = scope;
+		}
+
+		@Override
+		public byte prepareOrGenerateInvocation(CodeStream codeStream, byte opcode) {
+			TypeBinding[] tgtParams = this.originalParameters;
+			byte len = (byte) tgtParams.length;
+			// argument array:
+			codeStream.bipush(len);
+			codeStream.anewarray(this.scope.getJavaLangObject());
+			// fold array store into arguments on stack:
+			for (byte i = (byte) (len-1); i >= 0; i--) {
+				// argi, array
+				if (size(tgtParams[i]) == 1) {
+					codeStream.dup_x1();
+					// array, argi, array
+					codeStream.swap();
+				} else {
+					codeStream.dup_x2();
+					// array, argi, array
+					codeStream.dup_x2();
+					// array, array, argi, array
+					codeStream.pop();
+				}
+				// array, array, argi
+				if (tgtParams[i].isPrimitiveType())
+					codeStream.generateBoxingConversion(tgtParams[i].id); // no longer need to handle 2-byte values
+				codeStream.bipush(i);
+				// array, array, argi, i
+				codeStream.swap();
+				// array, array, i, argi
+				codeStream.aastore();
+				// array
+			}
+			// array (containing all arguments)
+
+			// accessId:
+			codeStream.bipush((byte) this.accessId);
+			codeStream.swap();
+			// accessId, array
+			
+			// opKind (ignored):
+			codeStream.iconst_0();
+			codeStream.swap();
+			// accessId, opKind, array
+
+			// enclosing team instance:
+			Object[] emulationPath = this.scope.getEmulationPath(this.enclosingTeam, true /*only exact match*/, false/*consider enclosing arg*/);
+			codeStream.generateOuterAccess(emulationPath, this.site, this.enclosingTeam, this.scope);
+			// invoke it:
+			byte invoke = this.targetMethod.isStatic() ? Opcodes.OPC_invokestatic : Opcodes.OPC_invokevirtual;
+			codeStream.invoke(invoke, this, this.targetMethod.declaringClass);
+			// convert result?:
+			if (this.originalReturnType != TypeBinding.VOID) {
+				if (this.originalReturnType.isBaseType()) {
+					codeStream.checkcast(this.scope.environment().computeBoxingType(this.originalReturnType));
+					codeStream.generateUnboxingConversion(this.originalReturnType.id);
+				} else {
+					codeStream.checkcast(this.originalReturnType);
+				}
+			} else {
+				codeStream.pop();
+			}
+			return 0; // signal we're done
+		}
+	}
+	static int size(TypeBinding type) {
+		switch (type.id) {
+			case TypeIds.T_double :
+			case TypeIds.T_long :
+				return 2;
+			case TypeIds.T_void :
+				return 0;
+			default :
+				return 1;
+		}
+	}
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/SyntheticRoleBridgeMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/SyntheticRoleBridgeMethodBinding.java
index d1471cd..121a644 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/SyntheticRoleBridgeMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/SyntheticRoleBridgeMethodBinding.java
@@ -17,10 +17,12 @@
 package org.eclipse.objectteams.otdt.internal.core.compiler.lookup;
 
 import static org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.*;
+
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
 import org.eclipse.jdt.internal.compiler.codegen.Opcodes;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Scope;
 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
@@ -29,6 +31,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
 import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel;
+import org.eclipse.objectteams.otdt.internal.core.compiler.util.TSuperHelper;
 import org.eclipse.objectteams.otdt.internal.core.compiler.util.TypeAnalyzer;
 
 public class SyntheticRoleBridgeMethodBinding extends SyntheticOTMethodBinding {
@@ -36,7 +39,7 @@
 	public static final char[] PRIVATE = "$private$".toCharArray(); //$NON-NLS-1$
 
 	public SyntheticRoleBridgeMethodBinding(SourceTypeBinding declaringRole, ReferenceBinding originalRole, MethodBinding targetMethod, int bridgeKind) {
-		super(declaringRole, AccPublic|AccSynthetic, targetMethod.selector, targetMethod.parameters, targetMethod.returnType);
+		super(declaringRole, AccPublic|AccSynthetic, targetMethod.selector, originalParameters(targetMethod), originalReturnType(targetMethod));
 		this.purpose = bridgeKind;
 		switch (bridgeKind) {
 			case RoleMethodBridgeOuter:
@@ -53,15 +56,16 @@
 				break;
 			case RoleMethodBridgeInner:
 				// correction: add role as first parameter:
-				len = targetMethod.parameters.length;
+				len = this.parameters.length;
 				int offset = targetMethod.isStatic()?2:0;
-				this.parameters = new TypeBinding[len+1+offset];
-				this.parameters[0] = originalRole.getRealType();
+				TypeBinding[] newParameters = new TypeBinding[len+1+offset];
+				newParameters[0] = originalRole.getRealType();
 				if (offset > 0) {
-					this.parameters[1] = TypeBinding.INT;				// dummy int
-					this.parameters[2] = originalRole.enclosingType(); // team arg
+					newParameters[1] = TypeBinding.INT;				// dummy int
+					newParameters[2] = originalRole.enclosingType(); // team arg
 				}
-				System.arraycopy(targetMethod.parameters, 0, this.parameters, 1+offset, len);
+				System.arraycopy(this.parameters, 0, newParameters, 1+offset, len);
+				this.parameters = newParameters;
 				// correction: this bridge is static:
 				this.modifiers |= AccStatic;
 				// correction: generate the bridge method name:
@@ -76,6 +80,40 @@
 		this.index = methodId;
 	}
 
+	private static TypeBinding[] originalParameters(MethodBinding targetMethod) {
+		if (!TSuperHelper.isTSuper(targetMethod)) {
+			MethodBinding top = findTopMethod(targetMethod);
+			if (top != null)
+				return top.original().parameters;
+		}
+		return targetMethod.original().parameters;
+	}
+
+	private static TypeBinding originalReturnType(MethodBinding targetMethod) {
+		if (!TSuperHelper.isTSuper(targetMethod)) {
+			MethodBinding top = findTopMethod(targetMethod);
+			if (top != null)
+				return top.original().returnType;
+		}
+		return targetMethod.original().returnType;
+	}
+
+	static MethodBinding findTopMethod(MethodBinding targetMethod) {
+		while (targetMethod.copyInheritanceSrc != null)
+			targetMethod = targetMethod.copyInheritanceSrc;
+		tsupers: if (targetMethod.overriddenTSupers != null) {
+			for (int i = 0; i < targetMethod.overriddenTSupers.length; i++) {
+				MethodBinding cand = targetMethod.overriddenTSupers[i];
+				if (!(cand instanceof ParameterizedMethodBinding)) {
+					targetMethod = cand;
+					break tsupers;
+				}
+			}
+			if (targetMethod.overriddenTSupers.length > 0)
+				targetMethod = targetMethod.overriddenTSupers[0];
+		}
+		return targetMethod;
+	}
 	@Override
 	public void generateInstructions(CodeStream codeStream) {
 		TypeBinding[] arguments = this.parameters;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/SyntheticRoleFieldAccess.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/SyntheticRoleFieldAccess.java
index e1cb40a..ffb6992 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/SyntheticRoleFieldAccess.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/SyntheticRoleFieldAccess.java
@@ -66,7 +66,7 @@
  *
  * @author stephan
  */
-public class SyntheticRoleFieldAccess extends SyntheticMethodBinding {
+public class SyntheticRoleFieldAccess extends SyntheticOTTargetMethod {
 
 	static final char[] FIELD_GET_NAME = "_fieldget_".toCharArray(); //$NON-NLS-1$
 	static final char[] FIELD_GET_PREFIX = CharOperation.concat(
@@ -264,7 +264,7 @@
 	 *
 	 * @param codeStream
 	 */
-	public void generateInvoke(CodeStream codeStream) {
+	public byte prepareOrGenerateInvocation(CodeStream codeStream, byte opcode) {
 		ReferenceBinding roleType = (ReferenceBinding)this.parameters[0];
 		if (roleType instanceof UnresolvedReferenceBinding) {
 			try {
@@ -272,7 +272,7 @@
 									.resolve(Config.getLookupEnvironment(), false);
 			} catch (NotConfiguredException e) {
 				e.logWarning("Failed to generate accessor"); //$NON-NLS-1$
-				return;
+				return opcode;
 			}
 			this.parameters[0] = roleType;
 		}
@@ -301,6 +301,7 @@
 			if (arg.initializationPCs != null) // null checking is asymmetric in LocalVariableBinding.
 				arg.recordInitializationEndPC(codeStream.position);
 		}
+		return 0; // done
 	}
 
 	private void insertOuterAccess(CodeStream codeStream, ReferenceBinding roleType)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/TeamAnchor.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/TeamAnchor.java
index 2872892..04b31e6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/TeamAnchor.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/TeamAnchor.java
@@ -799,7 +799,7 @@
 			LookupEnvironment   env) 
 	{
 	    DependentTypeBinding dependentTypeBinding =
-	    	(DependentTypeBinding)env.createParameterizedType(typeBinding, arguments, this, paramPosition, typeBinding.enclosingType(), Binding.NO_ANNOTATIONS);
+	    	(DependentTypeBinding)env.createParameterizedType(typeBinding, arguments, this, paramPosition, typeBinding.enclosingType(), typeBinding.getTypeAnnotations());
 	    return (dimensions > 0)
 	    	? dependentTypeBinding.getArrayType(dimensions)
 	    	: dependentTypeBinding;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementor.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementor.java
index 40e04e6..f72a8b8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementor.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementor.java
@@ -516,7 +516,7 @@
 				callinBindingDeclaration,
 				callinWrapperDecl,
 				baseMethodSpec,
-				false,
+				null,
 				resultName != null /*hasResultArg*/);
         if (messageSendArguments == null) {
         	callinBindingDeclaration.tagAsHavingErrors();
@@ -773,6 +773,7 @@
 			TypeBinding[] typeArguments = liftMethod[0].typeVariables();
 			if (typeArguments != Binding.NO_TYPE_VARIABLES)
 				try {
+					// FIXME: pass null annotations, once JDT supports those on a type declaration.
 					roleVarType = Config.getLookupEnvironment().createParameterizedType(roleVarType, typeArguments, null, -1, roleModel.getBinding().enclosingType(), Binding.NO_ANNOTATIONS);
 				} catch (NotConfiguredException e) {
 					e.logWarning("Cannot lookup parameterized type"); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
index cdbb466..c422134 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
@@ -308,7 +308,10 @@
 		// we probably want to avoid generating empty methods here.
 		final TypeDeclaration teamDecl = aTeam.getAst();
 		if (teamDecl == null) return;
+
 		final AstGenerator gen = new AstGenerator(teamDecl);
+		gen.replaceableEnclosingClass = teamDecl.binding;
+
 		
 		// public void _OT$callBefore   (IBoundBase2 base, 							int boundMethodId, int callinId, 	Object[] args)
 		// public void _OT$callAfter	(IBoundBase2 base, 							int boundMethodId, int callinId, 	Object[] args, Object result)
@@ -387,7 +390,6 @@
 						boolean isStaticRoleMethod = callinDecl.getRoleMethod().isStatic();
 						ReferenceBinding roleType = callinDecl.scope.enclosingReceiverType();
 						MethodBinding roleMethodBinding = callinDecl.getRoleMethod();
-	
 						
 						boolean needLiftedRoleVar = !isStaticRoleMethod
 												&& roleType.isCompatibleWith(roleMethodBinding.declaringClass);
@@ -615,7 +617,7 @@
 								//   who is responsible for lowering: the team or the current role?
 								Expression lowerReceiver = (isRoleOfCurrentRole(roleType, returnTypes[0]))
 										? gen.singleNameReference(roleVar)
-										: gen.thisReference();
+										: genTeamThis(gen, returnTypes[0]);
 								result = new Lowering().lowerExpression(methodDecl.scope, result, returnTypes[0], returnTypes[1],
 										lowerReceiver, true/*needNullCheck*/, true/*delayedResolve*/);
 							}
@@ -904,7 +906,7 @@
 										gen.castExpression(gen.singleNameReference(IOTConstants.BASE), gen.typeReference(currentRole.baseclass()), CastExpression.RAW),
 										currentRole.baseclass(), currentRole, false)
 								// TODO: might want to extend the signature of callNext to pass the current role to avoid this lifting?
-					: gen.thisReference();
+					: genTeamThis(gen, returnTypes[0]);
 				result = Lifting.liftCall(mapping.scope,
 										  liftReceiver,
 										  gen.castExpression(result,
@@ -933,6 +935,16 @@
 		AstEdit.addMethod(teamDecl, decl);
 	}
 
+	Reference genTeamThis(AstGenerator gen, TypeBinding type) {
+		TypeBinding leaf = type.leafComponentType();
+		if (leaf instanceof ReferenceBinding) {
+			ReferenceBinding teamBinding = ((ReferenceBinding) leaf).enclosingType();
+			if (teamBinding != null)
+				return gen.qualifiedThisReference(teamBinding);
+		}
+		return gen.thisReference();
+	}
+
 	TypeBinding[] getReturnTypes(CallinMappingDeclaration mapping, int i) {
 		TypeBinding baseReturn = mapping.baseMethodSpecs[i].resolvedType();
 		TypeBinding roleReturn = mapping.roleMethodSpec.resolvedType();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
index 2530885..af89674 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
@@ -68,6 +68,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec.ImplementationStrategy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.ParameterMapping;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.PotentialLowerExpression;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.PrivateRoleMethodCall;
@@ -533,7 +534,7 @@
                     		calloutDecl,
 							roleMethodDeclaration,
 							calloutDecl.roleMethodSpec,
-							(calloutDecl.baseMethodSpec instanceof FieldAccessSpec),
+							(calloutDecl.baseMethodSpec instanceof FieldAccessSpec) ? ((FieldAccessSpec)calloutDecl.baseMethodSpec) : null,
 							false /*hasResultArg*/);
 			if (   arguments == null
                 || hasParamMappingProblems(calloutDecl, returnType, roleMethodDeclaration.scope.problemReporter()))
@@ -558,7 +559,9 @@
 							CastExpression.DO_WRAP);
 
 		Expression baseAccess = null;
-		if (calloutDecl.baseMethodSpec.isPrivate() && baseType.isRole()) {
+		if (calloutDecl.baseMethodSpec.isPrivate() && baseType.isRole()
+				&& calloutDecl.baseMethodSpec.implementationStrategy != ImplementationStrategy.DYN_ACCESS)
+		{
     		// tricky case: callout to a private role method (base-side)
     		// requires the indirection via two wrapper methods (privateBridgeMethod)
 
@@ -975,10 +978,12 @@
 		int l= result.length;
 		if (result == Binding.NO_PARAMETERS || l == 0)
 			return result;
-		System.arraycopy(result, 0, result= new TypeBinding[l], 0, l);
 		TypeVariableBinding[] variables= wrapperMethod.binding.typeVariables();
-		for (int i = 0; i < result.length; i++)
-			result[i] = substituteVariables(result[i], variables);
+		if (variables != Binding.NO_TYPE_VARIABLES) {
+			System.arraycopy(result, 0, result= new TypeBinding[l], 0, l);
+			for (int i = 0; i < result.length; i++)
+				result[i] = substituteVariables(result[i], variables);
+		}
 		return result;
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementorDyn.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementorDyn.java
index 9d7e7e7..9dda280 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementorDyn.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementorDyn.java
@@ -1,7 +1,7 @@
 /**********************************************************************
  * This file is part of "Object Teams Development Tooling"-Software
  * 
- * Copyright 2011 GK Software AG and others.
+ * Copyright 2011, 2014 GK Software AG and others.
  * 
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -48,7 +48,7 @@
 												  Expression receiver, MethodSpec baseSpec, Expression[] arguments,
 												  AstGenerator gen) 
 	{
-		char[] selector = ensureAccessor(scope, baseType, baseSpec.isStatic());
+		char[] selector = ensureAccessor(scope, baseType, baseSpec.isStatic()).selector;
 		TeamModel teamModel = roleModel.getTeamModel();
 		Expression accessIdArg = gen.intLiteral(baseSpec.accessId);
 		int opKind = 0;
@@ -65,12 +65,14 @@
 			return gen.createCastOrUnboxing(messageSend, baseSpec.resolvedType(), true/*baseAccess*/);
 	}
 
-	private static char[] ensureAccessor(Scope scope, ReferenceBinding baseType, boolean isStatic) {
+	public static MethodBinding ensureAccessor(Scope scope, ReferenceBinding baseType, boolean isStatic) {
 		if (baseType.isRoleType())
 			baseType = baseType.getRealClass();
 		char[] selector = isStatic ? OT_ACCESS_STATIC : OT_ACCESS;
 		MethodBinding[] methods = baseType.getMethods(selector);
-		if (methods == null || methods.length != 1) {
+		if (methods != null && methods.length == 1) {
+			return methods[0];
+		} else {
 			int modifiers = ClassFileConstants.AccPublic|ClassFileConstants.AccSynthetic;
 			if (isStatic)
 				modifiers |= ClassFileConstants.AccStatic;
@@ -86,7 +88,7 @@
 						Binding.NO_EXCEPTIONS,
 						baseType);
 			baseType.addMethod(method);
+			return method;
 		}
-		return selector;
 	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/MethodMappingImplementor.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/MethodMappingImplementor.java
index 5518e15..297ca25 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/MethodMappingImplementor.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/MethodMappingImplementor.java
@@ -44,6 +44,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec.ImplementationStrategy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TypeAnchorReference;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
@@ -109,7 +110,7 @@
 			AbstractMethodMappingDeclaration methodMapping,
 			MethodDeclaration      wrapperMethodDeclaration,
 			MethodSpec             sourceMethodSpec,
-			boolean                isFieldAccess,
+			FieldAccessSpec			baseFieldSpec,
 			boolean                hasResultArgument)
 	{
 		// prepare parameter mappings:
@@ -120,7 +121,7 @@
 		}
 		
 	    Argument[]   wrapperMethodArguments = wrapperMethodDeclaration.arguments;
-	    Expression[] arguments;
+	    Expression[] arguments = null;
 
 	    boolean hasArgError = false;
 
@@ -135,25 +136,30 @@
     	int implementationArgLen = implParameters.length;
 
 		int expressionsOffset = 0;
-        if (isFieldAccess && this._role.getWeavingScheme() == WeavingScheme.OTRE) { // OTREDyn uses non-static accessor for non-static fields
-        	// field access is mapped to static method with additional first parameter _OT$base (unless static):
-        	if (!((FieldAccessSpec)methodMapping.getBaseMethodSpecs()[0]).isStatic())
-        		expressionsOffset = 1;
+        if (baseFieldSpec != null) {
+			if (baseFieldSpec.implementationStrategy == ImplementationStrategy.DYN_ACCESS) {
+				 // in decapsulation scenarios OTREDyn uses non-static accessor for non-static fields
+				if (!baseFieldSpec.isSetter())
+					implementationArgLen = 0; // if resolved to a 4-arg _OT$access, don't consider these args during AST gen.
+			} else if (this._role.getWeavingScheme() == WeavingScheme.OTRE 
+					&& !((FieldAccessSpec)methodMapping.getBaseMethodSpecs()[0]).isStatic()) {
+				// for OTRE, non-static field access is mapped to static method with additional first parameter _OT$base:
+				expressionsOffset = 1;
 
-        	ReferenceBinding baseType = methodMapping.scope.enclosingSourceType().baseclass();
-        	arguments = new Expression[implementationArgLen+expressionsOffset];
-        	if (expressionsOffset > 0) {
-	        	// TODO(SH): generalize this and the corresponding statement in
-	        	//           CalloutImplementor.makeArguments().
-	        	// cast needed against weakened _OT$base reference.
-	        	MethodSpec baseSpec = ((CalloutMappingDeclaration)methodMapping).baseMethodSpec;
-	        	AstGenerator gen = new AstGenerator(baseSpec);
-	    		arguments[0] = new CastExpression(
+				ReferenceBinding baseType = methodMapping.scope.enclosingSourceType().baseclass();
+				arguments = new Expression[implementationArgLen+expressionsOffset];
+		    	// TODO(SH): generalize this and the corresponding statement in
+		    	//           CalloutImplementor.makeArguments().
+		    	// cast needed against weakened _OT$base reference.
+		    	MethodSpec baseSpec = ((CalloutMappingDeclaration)methodMapping).baseMethodSpec;
+		    	AstGenerator gen = new AstGenerator(baseSpec);
+				arguments[0] = new CastExpression(
 						gen.singleNameReference(IOTConstants._OT_BASE),
 						gen.baseclassReference(baseType),
 						baseType.isRole() ? CastExpression.NEED_CLASS : CastExpression.RAW); // FIXME (see also CalloutImplementor.makeArguments)
-        	}
-        } else {
+			}
+		} 
+        if (arguments == null) {
         	arguments = new Expression[implementationArgLen];
         }
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/FieldModel.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/FieldModel.java
index 16d29eb..2b717ed 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/FieldModel.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/FieldModel.java
@@ -20,10 +20,10 @@
  **********************************************************************/
 package org.eclipse.objectteams.otdt.internal.core.compiler.model;
 
+import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.ANCHOR_USAGE_RANKS;
+import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.AccSynthIfc;
 import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.OT_GETFIELD;
 import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.OT_SETFIELD;
-import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.AccSynthIfc;
-import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.ANCHOR_USAGE_RANKS;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
@@ -33,12 +33,15 @@
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec.ImplementationStrategy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.AnchorUsageRanksAttribute;
 import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.WordValueAttribute;
+import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementorDyn;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel.FakeKind;
 
 
@@ -151,29 +154,36 @@
 	/** Create a faked method binding for a getAccessor to a given base field. 
 	 * @param isGetter select getter or setter
 	 */
-	public static MethodBinding getDecapsulatingFieldAccessor(ReferenceBinding baseType,
+	public static MethodBinding getDecapsulatingFieldAccessor(Scope scope,
+												         		  ReferenceBinding baseType,
 												         		  FieldBinding     resolvedField,
-												         		  boolean 		   isGetter)
+												         		  boolean 		   isGetter,
+												         		  ImplementationStrategy strategy)
 	{
 		FieldModel model = FieldModel.getModel(resolvedField);
 		MethodBinding accessor = isGetter ? model._decapsulatingGetter : model._decapsulatingSetter;
 		if (accessor != null)
 			return accessor;
 		
-		TypeBinding[] argTypes = resolvedField.isStatic() 
-									? (isGetter 
-											? new TypeBinding[0] 
-											: new TypeBinding[]{resolvedField.type})
-									: (isGetter
-											? new TypeBinding[]{baseType}
-											: new TypeBinding[]{baseType, resolvedField.type});
-		accessor = new MethodBinding(
+		if (strategy == ImplementationStrategy.DYN_ACCESS) {
+			accessor = CalloutImplementorDyn.ensureAccessor(scope, baseType, resolvedField.isStatic());
+		} else {
+			TypeBinding[] argTypes = resolvedField.isStatic() 
+										? (isGetter
+												? new TypeBinding[0]
+												: new TypeBinding[]{resolvedField.type})
+										: (isGetter
+												? new TypeBinding[]{baseType}
+												: new TypeBinding[]{baseType, resolvedField.type});
+			accessor = new MethodBinding(
 					ClassFileConstants.AccPublic|ClassFileConstants.AccStatic,
 					CharOperation.concat(isGetter ? OT_GETFIELD : OT_SETFIELD, resolvedField.name),
 					isGetter ? resolvedField.type : TypeBinding.VOID,
 					argTypes,
 					Binding.NO_EXCEPTIONS,
 					baseType);
+			baseType.addMethod(accessor);
+		}
 		MethodModel.getModel(accessor)._fakeKind = FakeKind.BASE_FIELD_ACCESSOR;
 		if (isGetter) 
 			model._decapsulatingGetter = accessor;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/copyinheritance/CopyInheritance.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/copyinheritance/CopyInheritance.java
index 7195ef5..57366a0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/copyinheritance/CopyInheritance.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/copyinheritance/CopyInheritance.java
@@ -1124,9 +1124,6 @@
 	    }
     	if (method.isPrivate()) {
     		newMethodDecl.binding.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; // don't warn unused copied method
-    		MethodBinding synthBinding = SyntheticRoleBridgeMethodBinding.findOuterAccessor(targetRoleDecl.scope, targetRoleDecl.binding, newMethodDecl.binding);
-    		if (synthBinding != null)
-    			synthBinding.parameters[0] = srcRole.getRealType(); // manual weakening of bridge to copy-inherited method
     	}
 
 	    newMethodDecl.binding.copiedInContext = tgtTeam.enclosingType();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java
index 858adea..96f5eb2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java
@@ -23,6 +23,7 @@
 import java.util.HashSet;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.Annotation;
 import org.eclipse.jdt.internal.compiler.ast.Argument;
@@ -573,19 +574,23 @@
 	{
 		/*
 		 * For the end of unregisterRole(Object) create:
-		 * 		if (first_cache != null) {
+		 * 		if (first_cache != null && found_base != null) { // ensure no null problems against either variable
 		 * 			first_cache.remove(_OT$base_arg);
 		 *          ((IBoundBase)found_base)._OT$removeRole(_OT$role_arg);
 		 *      }
 		 */
 		return gen.ifStatement(
-					new EqualExpression(
-						gen.singleNameReference(FIRST_CACHE),
-						gen.nullLiteral(),
-						OperatorIds.EQUAL_EQUAL
-					),
-					gen.block(null),
-					gen.block(new Statement[] { // "else" instead of negation
+					new AND_AND_Expression(
+						new EqualExpression(
+							gen.singleNameReference(FIRST_CACHE),
+							gen.nullLiteral(),
+							OperatorIds.NOT_EQUAL),
+						new EqualExpression(
+							gen.singleNameReference(FOUND_BASE),
+							gen.nullLiteral(),
+							OperatorIds.NOT_EQUAL),
+						OperatorIds.AND_AND),
+					gen.block(new Statement[] {
 						gen.messageSend(
 							gen.singleNameReference(FIRST_CACHE),
 							REMOVE,
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java
index de3310a..9b24699 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java
@@ -274,7 +274,11 @@
 		EqualExpression result = new EqualExpression(
 				value,
 				nullLiteral(),
-				OperatorIds.EQUAL_EQUAL);
+				OperatorIds.EQUAL_EQUAL) {
+			protected void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
+				// nop, never warn about generated null checks
+			}
+		};
 		result.sourceStart = this.sourceStart;
 		result.sourceEnd = this.sourceEnd;
 		result.constant = Constant.NotAConstant;
diff --git a/org.eclipse.jdt.core/grammar/java.g b/org.eclipse.jdt.core/grammar/java.g
index 6eacdc8..8be7063 100644
--- a/org.eclipse.jdt.core/grammar/java.g
+++ b/org.eclipse.jdt.core/grammar/java.g
@@ -404,6 +404,9 @@
 TypeAnnotationsopt ::= $empty
 /.$putCase consumeZeroTypeAnnotations(); $break ./
 TypeAnnotationsopt -> TypeAnnotations
+--{ObjectTeams: after TentativeTypeAnchor confirm that it was a *type annotation*:
+/.$putCase confirmTypeAnnotation(); $break ./
+-- SH}
 /:$compliance 1.8:/
 /:$readableName TypeAnnotationsopt:/
 
@@ -2601,12 +2604,13 @@
 -- ==== No Nested Generics ====
 -- case 1: it was indeed a type anchor:
 TypeAnchorOrAnnotatedTypeArgument -> AnyTypeAnchor
--- case 2a: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
-TypeAnchorOrAnnotatedTypeArgument -> TentativeTypeAnchor NotAnAnchor ReferenceType
+/.$putCase confirmTypeAnchor(); $break ./
+-- case 2a: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
+TypeAnchorOrAnnotatedTypeArgument ::= TentativeTypeAnchor NotAnAnchor ReferenceType
 /.$putCase consumeTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
 /:$compliance 1.5:/
--- case 2b: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+-- case 2b: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument -> TentativeTypeAnchor NotAnAnchor Wildcard
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
@@ -2615,12 +2619,15 @@
 -- ==== One Level Nested Generics ====
 -- case 1: it was indeed a type anchor:
 TypeAnchorOrAnnotatedTypeArgument1 -> AnyTypeAnchor '>'
--- case 2a: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+/.$putCase confirmTypeAnchor(); $break ./
+/:$readableName TypeAnchor:/
+/:$compliance 1.5:/
+-- case 2a: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument1 -> TentativeTypeAnchor NotAnAnchor ReferenceType1
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
 /:$compliance 1.5:/
--- case 2b: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+-- case 2b: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument1 -> TentativeTypeAnchor NotAnAnchor Wildcard1
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
@@ -2629,12 +2636,15 @@
 -- ==== Two Levels Nested Generics ====
 -- case 1: it was indeed a type anchor:
 TypeAnchorOrAnnotatedTypeArgument2 -> AnyTypeAnchor '>>'
--- case 2a: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+/.$putCase confirmTypeAnchor(); $break ./
+/:$readableName TypeAnchor:/
+/:$compliance 1.5:/
+-- case 2a: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument2 -> TentativeTypeAnchor NotAnAnchor ReferenceType2
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
 /:$compliance 1.5:/
--- case 2b: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+-- case 2b: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument2 -> TentativeTypeAnchor NotAnAnchor Wildcard2
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
@@ -2643,19 +2653,22 @@
 -- ==== Three Levels Nested Generics ====
 -- case 1: it was indeed a type anchor:
 TypeAnchorOrAnnotatedTypeArgument3 -> AnyTypeAnchor '>>>'
--- case 2a: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+/.$putCase confirmTypeAnchor(); $break ./
+/:$readableName TypeAnchor:/
+/:$compliance 1.5:/
+-- case 2a: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument3 -> TentativeTypeAnchor NotAnAnchor ReferenceType3
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
 /:$compliance 1.5:/
--- case 2b: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+-- case 2b: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument3 -> TentativeTypeAnchor NotAnAnchor Wildcard3
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
 /:$compliance 1.5:/
 -- =====================================
 
--- trigger converting a mistaken type anchor into a type argument
+-- trigger converting a mistaken type anchor into a type annotation on a type argument
 NotAnAnchor ::= $empty
 /.$putCase convertTypeAnchor(0); $break ./
 /:$readableName annotatedTypeArgument:/
diff --git a/org.eclipse.jdt.core/scripts/export-ecj.xml b/org.eclipse.jdt.core/scripts/export-ecj.xml
index d82ba60..921c94b 100644
--- a/org.eclipse.jdt.core/scripts/export-ecj.xml
+++ b/org.eclipse.jdt.core/scripts/export-ecj.xml
@@ -48,7 +48,7 @@
 		<property name="target.folder" value="${basedir}/bin"/>
 		<replace file="${target.folder}/org/eclipse/jdt/internal/compiler/batch/messages.properties" token="bundle_qualifier" value="${bundleVersionQualifer}"/>
 <!-- {ObjectTeams: more replacement (strategy no longer maintained in JDT?) -->
-		<replace file="${target.folder}/org/eclipse/jdt/internal/compiler/batch/messages.properties" token="bundle_version" value="${bundleVersion}"/>
+		<replace file="${target.folder}/org/eclipse/jdt/internal/compiler/batch/messages.properties" token="bundle_version" value="${bundleVersionMajor}.${bundleVersionMinor}.${bundleVersionService}"/>
 <!-- SH}-->
 		<echo message="Extract .class file and properties for the batch compiler" />
 		<copy todir="${ecj-temp-folder}">
diff --git a/plugins/org.eclipse.objectteams.otdt/META-INF/MANIFEST.MF b/plugins/org.eclipse.objectteams.otdt/META-INF/MANIFEST.MF
index 357c527..8518f14 100644
--- a/plugins/org.eclipse.objectteams.otdt/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.objectteams.otdt/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.objectteams.otdt;singleton:=true
-Bundle-Version: 2.3.0.qualifier
+Bundle-Version: 2.3.1.qualifier
 Bundle-ClassPath: otdtcoreext.jar
 Bundle-Activator: org.eclipse.objectteams.otdt.core.ext.OTDTPlugin
 Bundle-Vendor: %providerName
diff --git a/plugins/org.eclipse.objectteams.otdt/about.ini b/plugins/org.eclipse.objectteams.otdt/about.ini
index 60b21f3..e883d2c 100644
--- a/plugins/org.eclipse.objectteams.otdt/about.ini
+++ b/plugins/org.eclipse.objectteams.otdt/about.ini
@@ -1,6 +1,6 @@
 aboutText=Object Teams Development Tooling\n\
 \n\
-Version: 2.3.0\n\
+Version: 2.3.1\n\
 \n\
 Part of the Eclipse Luna Simultaneous Release\n\
 \n\
diff --git a/plugins/org.eclipse.objectteams.otdt/src/org/eclipse/objectteams/otdt/core/ext/OTREContainer.java b/plugins/org.eclipse.objectteams.otdt/src/org/eclipse/objectteams/otdt/core/ext/OTREContainer.java
index c1c432b..b0705c8 100644
--- a/plugins/org.eclipse.objectteams.otdt/src/org/eclipse/objectteams/otdt/core/ext/OTREContainer.java
+++ b/plugins/org.eclipse.objectteams.otdt/src/org/eclipse/objectteams/otdt/core/ext/OTREContainer.java
@@ -21,6 +21,7 @@
 package org.eclipse.objectteams.otdt.core.ext;
 
 import java.io.IOException;
+import java.net.URL;
 
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.CoreException;
@@ -261,8 +262,12 @@
 			int i = 0;
 			BYTECODE_WEAVER_PATHS[asm][i++] = new Path(OTVariableInitializer.getInstallatedPath(OTDTPlugin.getDefault(), OTDRE_PLUGIN_NAME, "bin")); //$NON-NLS-1$
 			for (String bundleName : ASM_BUNDLE_NAMES) {
-				for (Bundle bundle : packageAdmin.getBundles(bundleName, ASM_VERSION_RANGE))	
-					BYTECODE_WEAVER_PATHS[asm][i++] = new Path(FileLocator.toFileURL(bundle.getEntry("/")).getFile()); //$NON-NLS-1$
+				for (Bundle bundle : packageAdmin.getBundles(bundleName, ASM_VERSION_RANGE)) {
+					URL bundleEntry = bundle.getEntry("bin"); // source project?
+					if (bundleEntry == null)
+						bundleEntry = bundle.getEntry("/"); // binary bundle
+					BYTECODE_WEAVER_PATHS[asm][i++] = new Path(FileLocator.toFileURL(bundleEntry).getFile()); //$NON-NLS-1$
+				}
 			}
 			if (i == 4)
 				break ASM;
diff --git a/plugins/org.eclipse.objectteams.otequinox/META-INF/MANIFEST.MF b/plugins/org.eclipse.objectteams.otequinox/META-INF/MANIFEST.MF
index cd8e62d..6dc3a87 100644
--- a/plugins/org.eclipse.objectteams.otequinox/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.objectteams.otequinox/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.objectteams.otequinox;singleton:=true
-Bundle-Version: 2.3.0.qualifier
+Bundle-Version: 2.3.1.qualifier
 Bundle-Activator: org.eclipse.objectteams.otequinox.TransformerPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/plugins/org.eclipse.objectteams.otequinox/META-INF/p2.inf b/plugins/org.eclipse.objectteams.otequinox/META-INF/p2.inf
index 08c8c87..a086d52 100644
--- a/plugins/org.eclipse.objectteams.otequinox/META-INF/p2.inf
+++ b/plugins/org.eclipse.objectteams.otequinox/META-INF/p2.inf
@@ -4,11 +4,11 @@
 
 
 units.0.id = org.eclipse.objectteams.otequinox.configuration
-units.0.version = 2.3.0.$qualifier$
+units.0.version = 2.3.1.$qualifier$
 
 units.0.hostRequirements.0.namespace=osgi.bundle
 units.0.hostRequirements.0.name=org.eclipse.objectteams.otequinox
-units.0.hostRequirements.0.range=[2.3.0,3.0.0)
+units.0.hostRequirements.0.range=[2.3.1,3.0.0)
 units.0.hostRequirements.1.namespace = org.eclipse.equinox.p2.eclipse.type
 units.0.hostRequirements.1.name = bundle
 units.0.hostRequirements.1.range = [1.0.0,2.0.0)
@@ -17,7 +17,7 @@
 units.0.properties.0.value = true
 units.0.requires.0.namespace = osgi.bundle
 units.0.requires.0.name = org.eclipse.objectteams.otequinox
-units.0.requires.0.range = [2.3.0,3.0.0)
+units.0.requires.0.range = [2.3.1,3.0.0)
 
 units.0.requires.1.namespace = org.eclipse.equinox.p2.eclipse.type
 units.0.requires.1.name = bundle
@@ -26,7 +26,7 @@
 
 units.0.provides.0.namespace = org.eclipse.equinox.p2.iu
 units.0.provides.0.name = org.eclipse.objectteams.otequinox.configuration
-units.0.provides.0.version = 2.3.0.$qualifier$
+units.0.provides.0.version = 2.3.1.$qualifier$
 
 units.0.instructions.install=\
 	installBundle(bundle:${artifact})
diff --git a/plugins/org.eclipse.objectteams.otequinox/about.ini b/plugins/org.eclipse.objectteams.otequinox/about.ini
index f04a271..0962c8c 100644
--- a/plugins/org.eclipse.objectteams.otequinox/about.ini
+++ b/plugins/org.eclipse.objectteams.otequinox/about.ini
@@ -1,6 +1,6 @@
 aboutText=Object Teams -- Equinox integration (OT/Equinox)\n\
 \n\
-Version: 2.3.0\n\
+Version: 2.3.1\n\
 \n\
 Part of the Eclipse Luna Simultaneous Release\n\
 \n\
diff --git a/plugins/org.eclipse.objectteams.otequinox/schema/aspectBindingNegotiators.exsd b/plugins/org.eclipse.objectteams.otequinox/schema/aspectBindingNegotiators.exsd
index 9d54188..2c646df 100644
--- a/plugins/org.eclipse.objectteams.otequinox/schema/aspectBindingNegotiators.exsd
+++ b/plugins/org.eclipse.objectteams.otequinox/schema/aspectBindingNegotiators.exsd
@@ -133,7 +133,7 @@
 which accompanies this distribution, and is available at
 &lt;a href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
 &lt;/p&gt;&lt;p&gt;
-Please visit &lt;a href=&quot;http://www.objectteams.org&quot;&gt;www.objectteams.org&lt;/a&gt; for updates and contact.
+Please visit &lt;a href=&quot;http://www.eclipse.org/objectteams&quot;&gt;www.eclipse.org/objectteams&lt;/a&gt; for updates and contact.
 &lt;/p&gt;&lt;p&gt;
 Contributors:&lt;br&gt;
 Technical University Berlin - Initial API and implementation
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java
index 0759da8..98ea905 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java
@@ -67,7 +67,7 @@
 		final List<TeamBinding> subTeams = new ArrayList<>();
 		Set<TeamBinding> equivalenceSet = new HashSet<>();
 
-		ActivationKind activation;
+		private ActivationKind activation; // clients must use accessor getActivation()!
 		boolean hasScannedBases;
 		boolean hasScannedRoles;
 
@@ -183,6 +183,16 @@
 		public String toString() {
 			return "team "+teamName+"("+(this.activation)+") super "+superTeamName;
 		}
+
+		/** Get the highest activation kind from this team and its equivalents. */
+		public ActivationKind getActivation() {
+			ActivationKind activation = this.activation;
+			for (TeamBinding equiv : this.equivalenceSet) {
+				if (equiv.activation.ordinal() > activation.ordinal())
+					activation = equiv.activation;
+			}
+			return activation;
+		}
 	}
 	
 	/**
@@ -228,7 +238,7 @@
 		@NonNull ActivationKind kind = ActivationKind.NONE;
 		try {
 			if (activationSpecifier != null)
-				kind = ActivationKind.valueOf(activationSpecifier);
+				kind = ActivationKind.valueOf(activationSpecifier); // well-known API of all enums
 		} catch (IllegalArgumentException iae) {	
 			log(iae, "Invalid activation kind "+activationSpecifier+" for team "+teamName);
 		}
@@ -278,7 +288,7 @@
 	/** If a given team requires no activation, check if its super team should be activated instead. */
 	public @Nullable TeamBinding getOtherTeamToActivate(TeamBinding team) {
 		TeamBinding superTeam = team.superTeam;
-		if (superTeam != null && superTeam.activation != ActivationKind.NONE) {
+		if (superTeam != null && superTeam.getActivation() != ActivationKind.NONE) {
 			return superTeam;
 		}
 		// sub teams?
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java
index 925ca14..5d9da54 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java
@@ -1,7 +1,7 @@
 /**********************************************************************
  * This file is part of "Object Teams Development Tooling"-Software
  * 
- * Copyright 2008, 2013 Technical University Berlin, Germany and others.
+ * Copyright 2008, 2014 Technical University Berlin, Germany and others.
  *  
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -45,7 +45,6 @@
 import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding.TeamBinding;
 import org.eclipse.objectteams.otequinox.Constants;
 import org.osgi.framework.Bundle;
-import org.osgi.service.packageadmin.PackageAdmin;
 
 /**
  * An instance of this class holds the information loaded from extensions
@@ -81,7 +80,7 @@
 	/* Load extensions for org.eclipse.objectteams.otequinox.aspectBindings and check aspect permissions. */
 	public void loadAspectBindings(
 			IExtensionRegistry extensionRegistry,
-			@SuppressWarnings("deprecation") @Nullable PackageAdmin packageAdmin,
+			@SuppressWarnings("deprecation") @Nullable org.osgi.service.packageadmin.PackageAdmin packageAdmin,
 			OTWeavingHook hook) 
 	{
 		IConfigurationElement[] aspectBindingConfigs = extensionRegistry
@@ -166,7 +165,7 @@
 	
 	@SuppressWarnings("deprecation") // multiple uses of deprecated but still recommended class PackageAdmin
 	private boolean checkRequiredFragments(String aspectBundleId, String baseBundleId, IConfigurationElement[] fragments, 
-			@Nullable PackageAdmin packageAdmin) 
+			@Nullable org.osgi.service.packageadmin.PackageAdmin packageAdmin) 
 	{
 		// checking only, no real action needed.
 		boolean hasError = false;
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectPermissionManager.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectPermissionManager.java
new file mode 100644
index 0000000..78343ab
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectPermissionManager.java
@@ -0,0 +1,644 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2009 Germany and Technical University Berlin, Germany.
+ * 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * Technical University Berlin - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.internal.osgi.weaving;
+
+import static org.eclipse.objectteams.otequinox.AspectPermission.DENY;
+import static org.eclipse.objectteams.otequinox.AspectPermission.GRANT;
+import static org.eclipse.objectteams.otequinox.AspectPermission.UNDEFINED;
+import static org.eclipse.objectteams.otequinox.TransformerPlugin.log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.eclipse.core.internal.runtime.InternalPlatform;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding.BaseBundle;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding.TeamBinding;
+import org.eclipse.objectteams.otequinox.ActivationKind;
+import org.eclipse.objectteams.otequinox.AspectBindingRequestAnswer;
+import org.eclipse.objectteams.otequinox.AspectPermission;
+import org.eclipse.objectteams.otequinox.Constants;
+import org.eclipse.objectteams.otequinox.IAspectRequestNegotiator;
+import org.eclipse.objectteams.otequinox.TransformerPlugin;
+import org.eclipse.osgi.internal.hookregistry.HookConfigurator;
+import org.eclipse.osgi.service.datalocation.Location;
+import org.objectteams.Team;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+/**
+ * Manage permissions of aspect bundles requesting to apply aspectBindings and forcedExports.
+ * The following pieces of information are checked:
+ * <ul>
+ * <li>properties set in installation-wide config.ini or as command line args (handled by {@link HookConfigurator} (plus internal class OTStorageHook))</li>
+ * <li>defaults set per workspace (file negotiationDefaults.txt)</li>
+ * <li>individual GRANT/DENY per workspace (files grantedForcedExports.txt, deniedForcedExports.txt)</li>
+ * <li>answers from registered negotiators (extension point org.eclipse.objectteams.otequinox.aspectBindingNegotiators, see {@link IAspectRequestNegotiator})</li>
+ * </ul>
+ *
+ * <p>
+ * The final answer for a given request is combined from all sources where the priority of any {@link #DENY} answer is highest, 
+ * of {@link #UNDEFINED} is lowest.
+ * </p>
+ * <p>
+ * If a negotiator has determined a decision and its answer has the <code>persistent</code> flag set,
+ * this particular aspect permission is stored as per-workspace configuration.
+ * </p>
+ * @author stephan
+ * @since 1.2.6
+ */
+@SuppressWarnings("restriction")
+@NonNullByDefault
+public class AspectPermissionManager {
+
+	// FIXME: forced exports are unimplemented as of OT/Equinox 2.3.0!
+
+	// property names for default configuration:
+	private static final String FORCED_EXPORT_DEFAULT  = "forced.export.default";
+	private static final String ASPECT_BINDING_DEFAULT = "aspect.binding.default";
+	
+	// workspace files where negotiation configuration is stored:
+	private static final String NEGOTIATION_DEFAULTS_FILE   = "negotiationDefaults.txt";  
+	private static final String GRANTED_FORCED_EXPORTS_FILE = "grantedForcedExports.txt";
+	private static final String DENIED_FORCED_EXPORTS_FILE  = "deniedForcedExports.txt";
+
+
+	// set of aspect plug-ins for which some permission has been denied:
+	private Set<String> deniedAspects = new HashSet<String>();
+	// default permission for aspect bindings:
+	private AspectPermission defaultAspectBindingPermission = GRANT;
+	// default permission for forced exports:
+	private AspectPermission defaultForcedExportPermission = UNDEFINED; // not yet granted, but open for receiving a GRANT
+	// for negotiation of aspect binding requests (incl. forced export):
+	private List<IAspectRequestNegotiator> negotiators = new ArrayList<IAspectRequestNegotiator>();
+	
+	
+	// collect all forced exports (denied/granted), granted should balance to an empty structure.
+	// structure is: aspect-id -> (base bundle x base package)*
+	private HashMap<String, ArrayList<String[]>> deniedForcedExportsByAspect= new HashMap<String, ArrayList<String[]>>();
+	private HashMap<String, ArrayList<String[]>> grantedForcedExportsByAspect= new HashMap<String, ArrayList<String[]>>();
+	
+	// key is aspectId+"->"+baseId, value is array of team names
+	private HashMap<String, Set<String>> deniedTeamsByAspectBinding = new HashMap<String, Set<String>>();
+	private HashMap<String, Set<String>> grantedTeamsByAspectBinding = new HashMap<String, Set<String>>();
+
+	// the workspace directory for storing the state of this plugin
+	@Nullable private IPath otequinoxState;
+	// back link needed for accessing the state location:
+	private Bundle transformerBundle;
+	// helper instance needed to stop bundles by name
+	@SuppressWarnings("deprecation")
+	@Nullable private org.osgi.service.packageadmin.PackageAdmin packageAdmin;
+	
+	public AspectPermissionManager(Bundle bundle, 
+			@SuppressWarnings("deprecation") @Nullable org.osgi.service.packageadmin.PackageAdmin packageAdmin)
+	{
+		this.transformerBundle = bundle;
+		this.packageAdmin = packageAdmin;
+	}
+
+	/* local cache for isReady(): */
+	private boolean isWaitingForLocation = true;
+	
+	/** Before using this permission manager a client must check whether we're ready (instance location set). */
+	public boolean isReady() {
+		if (!isWaitingForLocation)
+			return true;
+		try {
+			InternalPlatform platform = InternalPlatform.getDefault();
+			Location instanceLocation = platform.getInstanceLocation();
+			if (!instanceLocation.isSet())
+				return false; // not yet capable
+			this.isWaitingForLocation = false;
+			fetchAspectBindingPermssionsFromWorkspace();
+		} catch (NoClassDefFoundError ncdfe) {
+			log(IStatus.WARNING, "Optional class InternalPlatform not found, cannot access workspace location");
+			this.isWaitingForLocation = false;
+			return true;
+		}
+		if (!this.obligations.isEmpty())
+			for (Runnable job : this.obligations)
+				job.run();
+		return true;
+	}
+
+	/** 
+	 * Fetch stored permissions from this plugin's workspace state.
+	 * 
+	 * @pre instance location should be set (see {@link #isReady()}),
+	 *    otherwise will silently return without accessing workspace settings. 
+	 */
+	private void fetchAspectBindingPermssionsFromWorkspace() {
+		try {
+			@SuppressWarnings("null") // known API
+			@NonNull IPath state = InternalPlatform.getDefault().getStateLocation(this.transformerBundle, true);
+			this.otequinoxState = state;
+			internalFetchAspectBindingPermssionsFromWorkspace(state);
+		} catch (NoClassDefFoundError ncdfe) {
+			log(IStatus.WARNING, "Optional class InternalPlatform not found, cannot access workspace location");
+			return;
+		}
+	}
+
+	private void internalFetchAspectBindingPermssionsFromWorkspace(IPath state) {
+		// defaults:
+		IPath configFilePath = state.append(NEGOTIATION_DEFAULTS_FILE);
+		File configFile = new File(configFilePath.toOSString());		
+		if (configFile.exists()) {
+			Properties props = new Properties();
+			try {
+				try (FileInputStream inStream = new FileInputStream(configFile)) {
+					props.load(inStream);
+				}
+				String value = (String) props.get(ASPECT_BINDING_DEFAULT);
+				if (value != null)
+					try {
+						defaultAspectBindingPermission = AspectPermission.valueOf(value); // known API of all enums
+					} catch (IllegalArgumentException iae) {
+						defaultAspectBindingPermission = AspectPermission.DENY;
+						log(iae, "Cannot set default aspect permission from file "+NEGOTIATION_DEFAULTS_FILE+", assuming DENY.");
+					}
+				value = (String) props.get(FORCED_EXPORT_DEFAULT);
+				if (value != null)
+					try {
+						defaultForcedExportPermission = AspectPermission.valueOf(value); // known API of all enums
+					} catch (IllegalArgumentException iae) {
+						defaultForcedExportPermission = AspectPermission.DENY;
+						log(iae, "Cannot set default forced exports permission from file "+NEGOTIATION_DEFAULTS_FILE+", assuming DENY.");
+					}
+			} catch (IOException ioex) {
+				log(ioex, "Failed to read configuration file "+configFilePath.toOSString());
+			}
+		} else {
+			try {
+				File stateDir = new File(state.toOSString());
+				if (!stateDir.exists())
+					stateDir.mkdirs();
+				configFile.createNewFile();
+				writeNegotiationDefaults(configFile);
+			} catch (IOException ioex) {
+				log(ioex, "Failed to create configuration file "+configFilePath.toOSString());
+			}
+		}
+		
+//		// explicitly denied:
+//		configFilePath = this.otequinoxState.append(DENIED_FORCED_EXPORTS_FILE);
+//		configFile = new File(configFilePath.toOSString());
+//		if (configFile.exists())
+//			HookConfigurator.parseForcedExportsFile(configFile, DENY);
+		
+//		// explicitly granted:
+//		configFilePath = this.otequinoxState.append(GRANTED_FORCED_EXPORTS_FILE);
+//		configFile = new File(configFilePath.toOSString());
+//		if (configFile.exists())
+//			HookConfigurator.parseForcedExportsFile(configFile, GRANT);
+	}
+
+	private void writeNegotiationDefaults(File configFile)
+			throws IOException 
+	{
+		try (FileWriter writer = new FileWriter(configFile)) {
+			writer.append(ASPECT_BINDING_DEFAULT+'='+defaultAspectBindingPermission.toString()+'\n');
+			writer.append(FORCED_EXPORT_DEFAULT+'='+defaultForcedExportPermission.toString()+'\n');
+			writer.flush();
+		}
+		log(IStatus.INFO, "Created aspect binding defaults file "+configFile.getCanonicalPath());
+	}
+
+		
+	/** Load extensions for EP org.eclipse.objectteams.otequinox.aspectBindingNegotiators. */
+	public void loadAspectBindingNegotiators(IExtensionRegistry extensionRegistry) {
+		IConfigurationElement[] aspectBindingNegotiatorsConfigs = extensionRegistry.getConfigurationElementsFor(
+				Constants.TRANSFORMER_PLUGIN_ID, Constants.ASPECT_NEGOTIATOR_EXTPOINT_ID);		
+		for (int i = 0; i < aspectBindingNegotiatorsConfigs.length; i++) {
+			IConfigurationElement currentNegotiatorConfig = aspectBindingNegotiatorsConfigs[i];
+			try {
+				Object negotiator = currentNegotiatorConfig.createExecutableExtension("class");
+				if (negotiator != null)
+					this.negotiators.add(((IAspectRequestNegotiator)negotiator));
+			} catch (CoreException e) {
+				log(e, "Failed to instantiate extension "+currentNegotiatorConfig);
+			}
+		}
+	}
+
+	/** Delegatee of internal API {@link TransformerPlugin#isDeniedAspectPlugin(String)}. */
+	public boolean isDeniedAspectPlugin(String symbolicName) {
+		return this.deniedAspects.contains(symbolicName);
+	}
+
+	
+	/**
+	 * Check whether a given aspect requests forced exports from base, 
+	 * and whether these requests are granted/denied by checking all available sources.
+	 * 
+	 * Clients should ask {@link #isReady()} (ie., instance location is set) before calling this method,
+	 * otherwise workspace settings have to be silently ignored (any error should be signaled by client).
+	 * 
+	 * @param aspectId      symbolic name of the aspect bundle
+	 * @param baseBundleId  symbolic name of the bound base bundle
+     * @param forcedExports any forced exports requested in this aspect binding.
+	 * @return whether all requests (if any) have been granted
+	 */
+	public boolean checkForcedExports(String aspectId, String baseBundleId, @Nullable IConfigurationElement[] forcedExports) 
+	{
+		if (forcedExports == null || forcedExports.length == 0)
+			return true;
+		
+		ArrayList<String[]> deniedForcedExports = getConfiguredForcedExports(aspectId, DENY,  deniedForcedExportsByAspect);
+		ArrayList<String[]> grantedForcedExports= getConfiguredForcedExports(aspectId, GRANT, grantedForcedExportsByAspect);
+
+		// iterate all requested forcedExports to search for a matching permission:
+		for (IConfigurationElement forcedExport : forcedExports) { // [0..1] (as defined in the schema)
+			String forcedExportsRequest = forcedExport.getValue();
+			if (forcedExportsRequest == null)
+				continue;
+			for (@NonNull String singleForcedExportRequest : forcedExportsRequest.split(",")) // well-known API
+			{
+				singleForcedExportRequest = singleForcedExportRequest.trim(); // well-known API
+
+				String[] listEntry;
+				boolean grantReported = false;
+				AspectPermission negotiatedPermission = this.defaultForcedExportPermission;
+				
+				// DENY by default?
+				if (negotiatedPermission == DENY) {
+					log(IStatus.ERROR, "Default denial of forced export regarding package "+singleForcedExportRequest+
+									   " from bundle "+baseBundleId+" as requested by bundle "+aspectId+"; bundle not activated");
+					this.deniedAspects.add(aspectId); // keep for answering the TransformerHook.
+					return false; // NOPE!					
+				}
+				
+				// DENY from configuration?
+				listEntry = findRequestInList(baseBundleId, singleForcedExportRequest, deniedForcedExports);
+				if (listEntry != null) {
+					log(IStatus.ERROR, "Explicit denial of forced export regarding package "+singleForcedExportRequest+
+									   " from bundle "+baseBundleId+" as requested by bundle "+aspectId+"; bundle not activated");
+					this.deniedAspects.add(aspectId); // keep for answering the TransformerHook.
+					return false; // NOPE!
+				}
+
+				// GRANT from configuration?
+				listEntry = findRequestInList(baseBundleId, singleForcedExportRequest, grantedForcedExports);
+				if (listEntry != null) {
+					log(IStatus.INFO, "Forced export granted for "+aspectId+": "+singleForcedExportRequest+" (from bundle "+baseBundleId+")");
+					grantReported = true;
+					grantedForcedExports.remove(listEntry);
+					negotiatedPermission = GRANT;
+				}
+
+				// default and persistent configuration did not DENY, proceed to the negotiators:
+				boolean shouldPersist = false;
+				for (IAspectRequestNegotiator negotiator : this.negotiators) {
+					AspectBindingRequestAnswer answer = negotiator.checkForcedExport(aspectId, baseBundleId, singleForcedExportRequest, negotiatedPermission);
+					if (answer.permission.compareTo(negotiatedPermission) > 0) // increasing priority of answer?
+					{ 
+						shouldPersist = answer.persistent;
+						negotiatedPermission = answer.permission;
+						// locally store as default for subsequent requests (not persistent, see below):
+						if (answer.allRequests)
+							this.defaultForcedExportPermission = negotiatedPermission;
+						if (negotiatedPermission == DENY)
+							break; // end of discussion.
+					}
+				}
+
+				// make decision persistent?
+				if (shouldPersist && negotiatedPermission != UNDEFINED)
+					// FIXME(SH): handle "allRequests":
+					persistForcedExportsAnswer(aspectId, baseBundleId, singleForcedExportRequest, negotiatedPermission);
+				
+				// report:
+				if (negotiatedPermission == GRANT) {
+					if (!grantReported)
+						log(IStatus.INFO, "Negotiation granted forced export for "+aspectId+
+										  ": "+singleForcedExportRequest+" (from bundle "+baseBundleId+')');
+				} else {
+					String verb = "did not grant";
+					if (negotiatedPermission == DENY)
+						verb = "denied";
+					log(IStatus.ERROR, "Negotiation "+verb+" forced export for "+aspectId+
+									   ": "+singleForcedExportRequest+" (from bundle "+baseBundleId+")"+
+									   ". Aspect is not activated.");
+					this.deniedAspects.add(aspectId); // keep for answering the TransformerHook.
+					return false; // don't install illegal aspect
+				}
+			}
+		}
+		if (!grantedForcedExports.isEmpty())
+			reportUnmatchForcedExports(aspectId, grantedForcedExports);
+		return true;
+	}
+
+	/**
+	 * Get the forced exports configured for a given aspect bundle with permission <code>perm</code>.
+	 * Consult {@link HookConfigurator} and store the result in <code>map</code>.
+	 * 
+	 * @param aspectId  symbolic name of the aspect in focus
+	 * @param perm		are we asking about DENY or GRANT?
+	 * @param map		in/out param for storing results from OTStorageHook
+	 * @return		 	list of pairs (base bundle x base package)
+	 */
+	private ArrayList<String[]> getConfiguredForcedExports(String                               aspectId, 
+														   AspectPermission 				    perm, 
+														   HashMap<String, ArrayList<String[]>> map) 
+    {
+		ArrayList<String[]> forcedExports= map.get(aspectId);
+		if (forcedExports == null) {
+			// fetch declarations from config.ini or other locations.
+// FIXME
+//			forcedExports= HookConfigurator.getForcedExportsByAspect(aspectId, perm);
+//			map.put(aspectId, forcedExports);
+			forcedExports = new ArrayList<String[]>();
+		}
+		return forcedExports;
+	}
+
+	private @Nullable String[] findRequestInList(String baseBundleId, String basePackage, @Nullable ArrayList<String[]> list) {
+		if (list != null)
+			for (String[] singleExport : list)
+				if (   singleExport[0].equals(baseBundleId)
+					&& singleExport[1].equals(basePackage))
+				{
+					return singleExport;
+				}
+		return null;
+	}
+
+	/**
+	 * If the structure of grantedForcedExports is not empty we have mismatches between forced-export declarations.
+	 * Report these mismatches as warnings.
+	 */
+	void reportUnmatchForcedExports(String aspectId, ArrayList<String[]> unmatchedForcedExports) 
+	{
+		for (String[] export: unmatchedForcedExports) {
+			String baseId = export[0];
+			String pack   = export[1];
+			log(IStatus.WARNING, "Aspect "+aspectId+
+							  " does not declare forced export of package "+
+							  pack+" from bundle "+baseId+
+							  " as declared in config.ini (or system property)");
+		}
+	}
+
+	/* Simple strategy to append a forced export to a file (existing or to be created). */
+	private void persistForcedExportsAnswer(String aspectId, String baseBundleId, String basePackage, AspectPermission negotiatedPermission) 
+	{
+		IPath state = this.otequinoxState;
+		if (state == null) {
+			log(IStatus.ERROR, "Can't persist forcedExports permission, no workspace location accessable.");
+			return;
+		}
+		try {
+			String fileName = (negotiatedPermission == DENY) ? DENIED_FORCED_EXPORTS_FILE : GRANTED_FORCED_EXPORTS_FILE;
+			IPath forcedExportsPath = state.append(fileName);
+			File forcedExportsFile = new File(forcedExportsPath.toOSString());
+			if (!forcedExportsFile.exists())
+				forcedExportsFile.createNewFile();
+			try (FileWriter writer = new FileWriter(forcedExportsFile, true)) { // FIXME(SH): consider merge (after decision about file format)
+				writer.append('\n');
+				writer.append(baseBundleId);
+				writer.append("\n[\n\t");
+				writer.append(basePackage);
+				writer.append(";x-friends:=\"");
+				writer.append(aspectId);
+				writer.append("\"\n]\n");
+				writer.flush();
+			}
+		} catch (IOException ioe) {
+			log(ioe, "Failed to persist negotiation result");
+		}
+	}
+	
+	/**
+	 * Check the permissions for all given teams.
+	 * @param aspectBundle the bundle containing the given teams
+	 * @param aspectBinding the binding mentioning the given teams
+	 * @param teamsForBase the teams to check
+	 * @return true if at least one binding was denied.
+	 */
+	boolean checkAspectPermissionDenial(Bundle aspectBundle, AspectBinding aspectBinding, Collection<TeamBinding> teamsForBase)
+	{
+		boolean hasDenial = false;
+		String aspectBundleName = aspectBundle.getSymbolicName();
+		if (aspectBundleName == null) {
+			log(IStatus.ERROR, "Cannot handle unnamed bundle "+aspectBundle);
+		} else {
+			for (TeamBinding teamForBase : teamsForBase)
+				if (!checkTeamBinding(aspectBundleName, aspectBinding.basePluginName, teamForBase.teamName)) {
+					hasDenial = true;
+					try {
+						aspectBundle.stop();
+						log(IStatus.ERROR, "Stopped bundle "+aspectBundleName+" which requests unconfirmed aspect binding(s).");
+					} catch (Throwable t) { // don't let the aspect bundle get by by throwing an unexpected exception!
+						log(t, "Failed to stop bundle "+aspectBundleName+" which requests unconfirmed aspect binding(s).");
+					}
+				}
+		}
+		return hasDenial;
+	}
+
+	/**
+	 * Check permission for the aspect binding of one specific team.
+	 * 
+	 * Clients should ask {@link #isReady()} (ie., instance location is set) before calling this method,
+	 * otherwise workspace settings have to be silently ignored (any error should be signaled by client).
+ 	 * 
+	 * @param aspectBundleId
+	 * @param baseBundleId
+	 * @param teamClass
+	 * @return whether this team is permitted to adapt classes from the given base bundle.
+	 */
+	boolean checkTeamBinding(String aspectBundleId, String baseBundleId, String teamClass) 
+	{
+		boolean shouldReportGrant = false; // grant by default should not be reported
+		AspectPermission negotiatedPermission = this.defaultAspectBindingPermission;
+
+		// DENY by default?
+		if (negotiatedPermission == DENY) {
+			log(IStatus.ERROR, "Default denial of aspect binding regarding base bundle "+baseBundleId+
+							   " as requested by bundle "+aspectBundleId+"; bundle not activated");
+			this.deniedAspects.add(aspectBundleId); // keep for answering the TransformerHook.
+			return false; // NOPE!					
+		}
+
+		
+		String key = aspectBundleId+"->"+baseBundleId;
+		
+		// denied from configuration?
+		Set<String> deniedTeams = deniedTeamsByAspectBinding.get(key);
+		if (deniedTeams != null && !deniedTeams.isEmpty()) {
+			if (deniedTeams.contains(teamClass)) {
+				deniedAspects.add(aspectBundleId);
+				return false;
+			}
+		}
+		
+		// granted from configuration?
+		Set<String> grantedTeams = grantedTeamsByAspectBinding.get(key);
+		if (grantedTeams != null && grantedTeams.contains(teamClass)) {
+			negotiatedPermission = GRANT;
+			shouldReportGrant = true;
+		}
+		
+		// default and persistent configuration did not DENY, proceed to the negotiators:
+		boolean shouldPersist = false;
+		String denyingNegotiator = null;
+		for (IAspectRequestNegotiator negotiator : this.negotiators) {
+			AspectBindingRequestAnswer answer = negotiator.checkAspectBinding(aspectBundleId, baseBundleId, teamClass, negotiatedPermission);
+			if (answer.permission.compareTo(negotiatedPermission) > 0) // increasing priority of answer?
+			{ 
+				shouldPersist = answer.persistent;
+				negotiatedPermission = answer.permission;
+				shouldReportGrant = negotiatedPermission == GRANT;
+				// locally store as default for subsequent requests:
+				if (answer.allRequests)
+					this.defaultAspectBindingPermission = negotiatedPermission;
+
+				if (negotiatedPermission == DENY) {
+					denyingNegotiator = negotiator.getClass().getName();
+					break; // end of discussion.
+				}
+			}
+		}
+
+		// make decision persistent?
+		if (shouldPersist && negotiatedPermission != UNDEFINED)
+			persistTeamBindingAnswer(aspectBundleId, baseBundleId, teamClass, negotiatedPermission);
+		
+		// report:
+		if (negotiatedPermission == GRANT) {
+			if (shouldReportGrant)
+				log(IStatus.INFO, "Negotiation granted aspect binding for "+aspectBundleId+
+								  " to base bundle "+baseBundleId+" by means of team "+teamClass+'.');
+		} else {
+			String front = (negotiatedPermission == DENY)
+					? "Negotiator "+denyingNegotiator + " denied" 
+					: "Negotiation did not grant";
+			log(IStatus.ERROR, front+" aspect binding for "+aspectBundleId+
+							   " to base bundle "+baseBundleId+" by means of team "+teamClass+
+							   ". Aspect is not activated.");
+			this.deniedAspects.add(aspectBundleId); // keep for answering the TransformerHook.
+			return false; // don't install illegal aspect
+		}
+		return true;
+	}
+
+	private void persistTeamBindingAnswer(String aspectBundleId, String baseBundleId, String teamClass, AspectPermission negotiatedPermission) 
+	{
+		// FIXME(SH): implement persisting these!		
+	}
+		
+	List<Runnable> obligations = new ArrayList<Runnable>();
+	public void addBaseBundleObligations(final List<Team> teamInstances, final Collection<TeamBinding> teamClasses, final Bundle aspectBundle, final BaseBundle baseBundle) {
+		schedule(new Runnable() {
+			public void run() {
+				List<TeamBinding> teamsToRevert = new ArrayList<TeamBinding>();
+				// aspect bindings:
+				String aspectBundleName = aspectBundle.getSymbolicName();
+				if (aspectBundleName == null) {
+					log(IStatus.ERROR, "Cannot handle unnamed aspect bundle "+aspectBundle);
+				} else {
+					for (TeamBinding teamClass : teamClasses)
+						if (!checkTeamBinding(aspectBundleName, baseBundle.bundleName, teamClass.teamName))
+							teamsToRevert.add(teamClass);
+				}
+				if (!teamsToRevert.isEmpty())
+					revert(teamsToRevert);
+			}
+			void revert(List<TeamBinding> teamsToRevert) {
+				try {
+					Set<Bundle> bundlesToStop = new HashSet<Bundle>();
+					for (TeamBinding teamClass : teamClasses) {
+						if (teamClass.getActivation() != ActivationKind.NONE) {
+							for (Team teamInstance : teamInstances)
+								if (teamInstance.getClass() == teamClass.teamClass)
+									teamInstance.deactivate(Team.ALL_THREADS);
+							// could also check if roles are present already ...
+						}
+						bundlesToStop.add(aspectBundle);
+					}
+					for (Bundle bundle : bundlesToStop) {
+						log(IStatus.ERROR, "Stopping aspect bundle "+bundle.getSymbolicName()+" with denied aspect binding(s)");
+						bundle.stop();
+					}
+				} catch (Exception e) {
+					log(e, "Failed to revert aspect bundle with denied aspect bindings.");
+				}
+			}
+		});
+	}
+
+	public void addForcedExportsObligations(final List<AspectBinding> aspects, final Bundle baseBundle) {
+		final String baseBundleName = baseBundle.getSymbolicName();
+		if (baseBundleName == null) {
+			log(IStatus.ERROR, "Cannot handle unnamed base bundle "+baseBundle);
+		} else {
+			schedule(new Runnable () {
+				public void run() {
+					for (AspectBinding aspectBinding : aspects)
+						if (!checkForcedExports(aspectBinding.aspectPlugin, baseBundleName, aspectBinding.forcedExports))
+							stopIllegalBundle(aspectBinding.aspectPlugin);
+				}
+			});
+		}
+	}
+
+	void schedule(Runnable job) {
+		if (isReady()) // became ready since last query?
+			job.run();
+		else
+			synchronized(obligations) {
+				obligations.add(job);
+			}
+	}
+		
+	void stopIllegalBundle(String symbolicName) {
+		String msgCore = "stop bundle "+symbolicName+" whose requests for forced exports have been denied";
+		@SuppressWarnings("deprecation")
+		org.osgi.service.packageadmin.PackageAdmin packAdmin = this.packageAdmin;
+		if (packAdmin == null) {
+			log(IStatus.ERROR, "Needing to "+msgCore+" but package admin is not available");
+		} else {
+			@SuppressWarnings("deprecation")
+			Bundle[] bundles = packAdmin.getBundles(symbolicName, null);
+			if (bundles == null)
+				log(IStatus.ERROR, "Needing to "+msgCore+" but bundle cannot be retrieved");
+			else
+				try {
+					bundles[0].stop();
+				} catch (BundleException e) {
+					log(e, "Failed to " + msgCore);
+				}
+		}
+	}
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java
index 8dba1fb..c3351d2 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java
@@ -27,7 +27,6 @@
 import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding.BaseBundle;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.hooks.weaving.WovenClass;
-import org.osgi.service.packageadmin.PackageAdmin;
 
 /**
  * Each instance of this class represents the fact that a given base bundle has aspect bindings,
@@ -38,7 +37,7 @@
 
 	private AspectBindingRegistry aspectBindingRegistry;
 	@SuppressWarnings("deprecation")
-	private @Nullable PackageAdmin admin;
+	private @Nullable org.osgi.service.packageadmin.PackageAdmin admin;
 
 	private String baseBundleName;	
 	@Nullable private BaseBundle baseBundle; // null when representing an aspectBundle with SELF-adapting teams
@@ -46,7 +45,7 @@
 	private List<AspectBinding> aspectBindings = new ArrayList<>();
 
 	public BaseBundleLoadTrigger(String bundleSymbolicName, @Nullable BaseBundle baseBundle, AspectBindingRegistry aspectBindingRegistry, 
-			@SuppressWarnings("deprecation") @Nullable PackageAdmin admin) 
+			@SuppressWarnings("deprecation") @Nullable org.osgi.service.packageadmin.PackageAdmin admin) 
 	{
 		this.baseBundleName = bundleSymbolicName;
 		this.baseBundle = baseBundle;
@@ -107,7 +106,7 @@
 
 				// (4) try optional steps:
 				TeamLoader loading = new TeamLoader(deferredTeamClasses, beingDefined, useDynamicWeaver);
-				loading.loadTeamsForBase(aspectBundle, aspectBinding, baseClass);
+				loading.loadTeamsForBase(aspectBundle, aspectBinding, baseClass, hook.getAspectPermissionManager());
 			}
 		}
 
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java
index 8ffe2c7..f5a26a6 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java
@@ -20,7 +20,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.instrument.IllegalClassFormatException;
-import java.security.ProtectionDomain;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -37,6 +36,7 @@
 import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding.BaseBundle;
 import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding.TeamBinding;
 import org.eclipse.objectteams.internal.osgi.weaving.Util.ProfileKind;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectPermissionManager;
 import org.eclipse.objectteams.otequinox.Constants;
 import org.eclipse.objectteams.otequinox.TransformerPlugin;
 import org.osgi.framework.Bundle;
@@ -48,8 +48,6 @@
 import org.osgi.framework.namespace.PackageNamespace;
 import org.osgi.framework.wiring.BundleWiring;
 import org.osgi.resource.Wire;
-import org.osgi.service.packageadmin.PackageAdmin;
-
 
 /**
  * This class integrates the OT/J weaver into OSGi using the standard API {@link WeavingHook}.
@@ -90,13 +88,17 @@
 
 	private @NonNull ASMByteCodeAnalyzer byteCodeAnalyzer = new ASMByteCodeAnalyzer();
 
+	private AspectPermissionManager permissionManager;
+
 	/** Call-back once the extension registry is up and running. */
 	public void activate(BundleContext bundleContext, ServiceReference<IExtensionRegistry> serviceReference) {
 		loadAspectBindingRegistry(bundleContext, serviceReference);
-		TransformerPlugin.getDefault().registerAspectBindingRegistry(this.aspectBindingRegistry);
+		TransformerPlugin activator = TransformerPlugin.getDefault();
+		activator.registerAspectBindingRegistry(this.aspectBindingRegistry);
+		activator.registerAspectPermissionManager(this.permissionManager);
 	}
 
-	// ====== Aspect Binding: ======
+	// ====== Aspect Bindings & Permissions: ======
 
 	@SuppressWarnings("deprecation")
 	private void loadAspectBindingRegistry(BundleContext context, ServiceReference<IExtensionRegistry> serviceReference) {
@@ -107,12 +109,24 @@
 			packageAdmin = (org.osgi.service.packageadmin.PackageAdmin)context.getService(ref);
 		else
 			log(IStatus.ERROR, "Failed to load PackageAdmin service. Will not be able to handle fragments.");
+		
 
 		IExtensionRegistry extensionRegistry = context.getService(serviceReference);
-		if (extensionRegistry == null)
+		if (extensionRegistry == null) {
 			log(IStatus.ERROR, "Failed to acquire ExtensionRegistry service, cannot load aspect bindings.");
-		else
+		} else {
+			permissionManager = new AspectPermissionManager(context.getBundle(), packageAdmin); // known API
+			permissionManager.loadAspectBindingNegotiators(extensionRegistry);
+
 			aspectBindingRegistry.loadAspectBindings(extensionRegistry, packageAdmin, this);
+		}
+	}
+
+	public @NonNull AspectPermissionManager getAspectPermissionManager() {
+		AspectPermissionManager manager = this.permissionManager;
+		if (manager == null)
+			throw new NullPointerException("Missing AspectPermissionManager");
+		return manager;
 	}
 
 	// ====== Base Bundle Trip Wires: ======
@@ -121,7 +135,8 @@
 	 * Callback during AspectBindingRegistry#loadAspectBindings():
 	 * Set-up a trip wire to fire when the mentioned base bundle is loaded.
 	 */
-	void setBaseTripWire(@SuppressWarnings("deprecation") @Nullable PackageAdmin packageAdmin, @NonNull String baseBundleId, BaseBundle baseBundle) 
+	void setBaseTripWire(@SuppressWarnings("deprecation") @Nullable org.osgi.service.packageadmin.PackageAdmin packageAdmin,
+			@NonNull String baseBundleId, BaseBundle baseBundle) 
 	{
 		if (!baseTripWires.containsKey(baseBundleId))
 			baseTripWires.put(baseBundleId, new BaseBundleLoadTrigger(baseBundleId, baseBundle, aspectBindingRegistry, packageAdmin));
@@ -380,5 +395,5 @@
 		}
 		return false;
 	}
-	
+
 }
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java
index 8805c8d..8f8512a 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java
@@ -70,11 +70,22 @@
 	 * Team loading, 1st attempt before the base class is even loaded
 	 * Trying to do these phases: load (now) instantiate/activate (if ready),
 	 */
-	public void loadTeamsForBase(Bundle aspectBundle, AspectBinding aspectBinding, WovenClass baseClass) {
+	public void loadTeamsForBase(Bundle aspectBundle, AspectBinding aspectBinding, WovenClass baseClass, AspectPermissionManager permissionManager) {
 		@SuppressWarnings("null")@NonNull String className = baseClass.getClassName();
 		Collection<TeamBinding> teamsForBase = aspectBinding.getTeamsForBase(className);
 		if (teamsForBase == null) 
 			return; // not done
+
+		// permission checking can be performed now or later, depending on readiness:
+		boolean permissionManagerReady = permissionManager.isReady();
+
+		// ==== check permissions before we start activating:
+		if (permissionManagerReady) { // otherwise we will register pending obligations below.
+			if (permissionManager.checkAspectPermissionDenial(aspectBundle, aspectBinding, teamsForBase))
+				return;
+		}
+		
+		List<Team> teamInstances = new ArrayList<>();
 		for (TeamBinding teamForBase : teamsForBase) {
 			if (teamForBase.isActivated) continue;
 			// Load:
@@ -85,12 +96,12 @@
 				continue;
 			}
 			// Try to instantiate & activate, failures are recorded in deferredTeams
-			ActivationKind activationKind = teamForBase.activation;
+			ActivationKind activationKind = teamForBase.getActivation();
 			if (activationKind == ActivationKind.NONE) {
 				teamForBase = aspectBinding.getOtherTeamToActivate(teamForBase);
 				if (teamForBase != null) {
 					if (teamForBase.isActivated) continue;
-					activationKind = teamForBase.activation;
+					activationKind = teamForBase.getActivation();
 					teamClass = teamForBase.loadTeamClass(aspectBundle);
 					if (teamClass == null) {
 						log(new ClassNotFoundException("Not found: "+teamForBase.teamName+" in bundle "+aspectBundle.getSymbolicName()), "Failed to load team "+teamForBase);
@@ -102,8 +113,13 @@
 			}
 			if (activationKind == ActivationKind.NONE) 
 				continue;
-			instantiateAndActivate(aspectBinding, teamForBase, activationKind);
+			Team instance = instantiateAndActivate(aspectBinding, teamForBase, activationKind);
+			if (instance != null)
+				teamInstances.add(instance);
 		}
+
+		if (!permissionManagerReady)
+			permissionManager.addBaseBundleObligations(teamInstances, teamsForBase, aspectBundle, aspectBinding.baseBundle);
 	}
 
 	public static @Nullable Pair<URL,String> findTeamClassResource(String className, Bundle bundle) {
@@ -153,7 +169,7 @@
 	/**
 	 * Check if the given team is ready. If so instantiate it and if activationKind requires also activate it.
 	 */
-	void instantiateAndActivate(AspectBinding aspectBinding, TeamBinding team, ActivationKind activationKind)
+	@Nullable Team instantiateAndActivate(AspectBinding aspectBinding, TeamBinding team, ActivationKind activationKind)
 	{
 		String teamName = team.teamName;
 		// don't try to instantiate before all base classes successfully loaded.
@@ -161,7 +177,7 @@
 			if (!isReadyToLoad(aspectBinding, team, teamName, activationKind)) {
 				if (this.useDynamicWeaving)
 					TeamManager.prepareTeamActivation(team.teamClass);
-				return;
+				return null;
 			}
 			for (TeamBinding equivalent : team.equivalenceSet)
 				equivalent.isActivated = true;
@@ -194,10 +210,12 @@
 				// application errors during activation
 				log(t, "Failed to activate team "+teamName);
 			}
+			return instance;
 		} catch (Throwable e) {
 			// application error during constructor execution?
 			log(e, "Failed to instantiate team "+teamName);
 		}
+		return null;
 	}
 
 	private boolean isReadyToLoad(AspectBinding aspectBinding,
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/AspectBindingRequestAnswer.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/AspectBindingRequestAnswer.java
new file mode 100644
index 0000000..e1be2d3
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/AspectBindingRequestAnswer.java
@@ -0,0 +1,48 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2009, 2014 Germany and Technical University Berlin, Germany.
+ * 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * Technical University Berlin - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otequinox;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+
+/** 
+ * Answer for an aspect binding request. See extension point org.eclipse.objectteams.otequinox.aspectBindingNegotiators.
+ * 
+ * @author stephan
+ * @since 1.2.6
+ */
+@NonNullByDefault
+public class AspectBindingRequestAnswer 
+{
+	/** Should this answer be remembered persistently? */
+	public boolean persistent;
+	/** Should this answer be applied to all subsequent requests? */
+	public boolean allRequests;
+	/** The actual answer. */
+	public AspectPermission permission;
+	
+	/**
+	 * @param persistent  Should this answer be remembered persistently?
+	 * @param allRequests Should this answer be applied to all subsequent requests?
+	 * @param permission  One of DENY, GRANT, UNDEFINED (let others decide).
+	 */
+	public AspectBindingRequestAnswer(boolean persistent, boolean allRequests, AspectPermission permission) {
+		this.persistent = persistent;
+		this.allRequests = allRequests;
+		this.permission = permission;
+	}
+	
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/AspectPermission.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/AspectPermission.java
new file mode 100644
index 0000000..a0ad44e
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/AspectPermission.java
@@ -0,0 +1,32 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2009, 2014 Technical University Berlin, Germany.
+ * 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * Technical University Berlin - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otequinox;
+
+/**
+ * Possible values while negotiating aspect access (aspectBinding and forcedExport).
+ * Note that order is relevant in this enum: higher index means higher priority.
+ * 
+ * @author stephan
+ * @since 1.2.6
+ */
+public enum AspectPermission {
+	/** Not influencing negotiation between other parties. */
+	UNDEFINED,
+	/** A permission is granted unless someone else denies it. */
+	GRANT, 
+	/** A permission is explicitly denied. Cannot be overridden. */
+	DENY;
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRegistry.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRegistry.java
index 0fc118a..3735251 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRegistry.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRegistry.java
@@ -63,5 +63,5 @@
 	 * @param symbolicName
 	 * @return
 	 */
-	public boolean isDeniedAspectPlugin(String symbolicName);
+	public boolean isDeniedAspectPlugin(@NonNull String symbolicName);
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRequestNegotiator.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRequestNegotiator.java
new file mode 100644
index 0000000..04024a1
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRequestNegotiator.java
@@ -0,0 +1,49 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2009, 2014 Germany and Technical University Berlin, Germany.
+ * 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * Technical University Berlin - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otequinox;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Interface for extenders wishing to participate in negotiation about aspect binding requests
+ * including forced exports.
+ * 
+ * @author stephan
+ * @since 1.2.6
+ */
+@NonNullByDefault
+public interface IAspectRequestNegotiator {
+	
+	/** 
+	 * Check whether a request for forced exports should be granted.
+	 * @param aspectBundleSymbolicName the aspect issuing the request
+	 * @param baseBundleSymbolicName   the affected base bundle
+	 * @param basePackage              the affected base package
+	 * @param previousNegotiation      the result of negotations up-to this point
+	 * @return a structure holding the answer
+	 */
+	AspectBindingRequestAnswer checkForcedExport(String aspectBundleSymbolicName, String baseBundleSymbolicName, String basePackage, AspectPermission previousNegotiation);
+
+	/** 
+	 * Check whether a request for an aspect binding should be granted.
+	 * @param aspectBundleSymbolicName the aspect issuing the request
+	 * @param baseBundleSymbolicName   the affected base bundle
+	 * @param teamClass 	           an affecting team class involved in this aspect binding
+	 * @param previousNegotiation      the result of negotations up-to this point
+	 * @return a structure holding the answer
+	 */
+	AspectBindingRequestAnswer checkAspectBinding(String aspectBundleSymbolicName, String baseBundleSymbolicName, String teamClass, AspectPermission previousNegotiation);
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java
index 690f558..d3c8aa6 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java
@@ -27,6 +27,7 @@
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding;
 import org.eclipse.objectteams.internal.osgi.weaving.AspectBindingRegistry;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectPermissionManager;
 import org.eclipse.objectteams.internal.osgi.weaving.OTWeavingHook;
 import org.eclipse.objectteams.otre.ClassLoaderAccess;
 import org.objectteams.Team;
@@ -54,6 +55,7 @@
 	
 	private AspectBindingRegistry aspectBindingRegistry;
 	private List<Team> teamInstances = new ArrayList<>();
+	private AspectPermissionManager aspectPermissionManager;
 
 	/*
 	 * (non-Javadoc)
@@ -192,6 +194,10 @@
 		this.aspectBindingRegistry = aspectBindingRegistry;
 	}
 
+	public void registerAspectPermissionManager(AspectPermissionManager permissionManager) {
+		this.aspectPermissionManager = permissionManager;
+	}
+
 	/**
 	 * public API:
 	 * {@link IAspectRegistry#getAdaptingAspectPlugins(Bundle)} 
@@ -222,8 +228,7 @@
 
 	@Override
 	public boolean isOTDT() {
-		// TODO Auto-generated method stub
-		return false;
+		return this.aspectBindingRegistry.isOTDT();
 	}
 
 	@Override
@@ -233,8 +238,7 @@
 
 	@Override
 	public String[] getAdaptedBasePlugins(Bundle aspectBundle) {
-		// TODO Auto-generated method stub
-		return null;
+		return this.aspectBindingRegistry.getAdaptedBasePlugins(aspectBundle);
 	}
 
 	@Override
@@ -244,8 +248,7 @@
 	}
 
 	@Override
-	public boolean isDeniedAspectPlugin(String symbolicName) {
-		// TODO Auto-generated method stub
-		return false;
+	public boolean isDeniedAspectPlugin(@NonNull String symbolicName) {
+		return aspectPermissionManager.isDeniedAspectPlugin(symbolicName);
 	}
 }
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java
index 2d068bd..cf22779 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java
@@ -160,7 +160,7 @@
 	private AbstractBoundClass enclosingClass;
 	private Map<String, Method> methods;
 	private Map<String, Field> fields;
-	private Map<AbstractBoundClass, Object> subclasses;
+	protected Map<AbstractBoundClass, Object> subclasses;
 	
 	// Is the java class, that was represented by the AbstractBoundClass
 	// already loaded by a class loader or not
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractTeam.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractTeam.java
index 0de7c51..6f959e7 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractTeam.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractTeam.java
@@ -16,12 +16,18 @@
  **********************************************************************/

 package org.eclipse.objectteams.otredyn.bytecode;

 

+import java.util.ArrayList;

 import java.util.Collection;

+import java.util.Collections;

+import java.util.List;

 import java.util.Set;

 import java.util.TreeSet;

 

 import org.eclipse.objectteams.otredyn.runtime.IBinding;

+import org.eclipse.objectteams.otredyn.runtime.IBoundClass;

 import org.eclipse.objectteams.otredyn.runtime.IBoundTeam;

+import org.eclipse.objectteams.otredyn.runtime.IClassIdentifierProvider;

+import org.eclipse.objectteams.otredyn.runtime.IClassRepository;

 

 /**

  * Represents a team class and stores the bindings this team has got.

@@ -77,4 +83,33 @@
 	public int getHighestAccessId() {

 		return highestAccessId;

 	}

+

+	/** Answer known tsub-versions of the given role. */

+	private List<String> getTSubRoles(String simpleRoleName) {

+		List<String> result = new ArrayList<String>();

+		for (AbstractBoundClass subTeam : this.subclasses.keySet()) {

+			if (!subTeam.isAnonymous())

+				result.add(subTeam.getName()+'$'+simpleRoleName);

+		}

+		return result;

+	}

+

+	/**

+	 * {@inheritDoc}

+	 */

+	@Override

+	public List<IBoundClass> getTSubsOfThis(IClassRepository classRepository, IClassIdentifierProvider idProvider) {

+		String name = this.getName();

+		int dollar = name.lastIndexOf('$');

+		if (dollar == -1)

+			return Collections.emptyList();

+		String teamName = name.substring(0, dollar);

+		// FIXME: use the idProvider, but: we don't yet have that team class :(

+		IBoundTeam myTeam = classRepository.getTeam(teamName.replace('/', '.'), teamName.replace('.', '/'), this.loader);

+		List<String> tsubRoleNames = ((AbstractTeam)myTeam).getTSubRoles(name.substring(dollar+1));

+		List<IBoundClass> tsubBases = new ArrayList<IBoundClass>();

+		for  (String tsubRoleName : tsubRoleNames)

+			tsubBases.add(classRepository.getBoundClass(tsubRoleName.replace('/', '.'), tsubRoleName.replace('.', '/'), this.loader));

+		return tsubBases;

+	}

 }

diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/OtreRedefineStrategy.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/OtreRedefineStrategy.java
index 7f854cf..41f6b58 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/OtreRedefineStrategy.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/OtreRedefineStrategy.java
@@ -30,7 +30,14 @@
 

 	public void redefine(Class<?> clazz, byte[] bytecode) throws ClassNotFoundException, UnmodifiableClassException {

 		ClassDefinition arr_cd[] = { new ClassDefinition(clazz, bytecode) };

-		otreAgent.getInstrumentation().redefineClasses(arr_cd);

+		try {

+			otreAgent.getInstrumentation().redefineClasses(arr_cd);

+		} catch (ClassFormatError cfe) {

+			// error output during redefinition tends to swallow the stack, print it now:

+			System.err.println("Error redifining "+clazz.getName());

+			cfe.printStackTrace();

+			throw cfe;

+		}

 	}

 

 }

diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmTypeHelper.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmTypeHelper.java
index d59fcb1..5528322 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmTypeHelper.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmTypeHelper.java
@@ -1,7 +1,7 @@
 /**********************************************************************

  * This file is part of "Object Teams Dynamic Runtime Environment"

  * 

- * Copyright 2009, 2012 Oliver Frank and others.

+ * Copyright 2009, 2014 Oliver Frank and others.

  * 

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License v1.0

@@ -27,6 +27,14 @@
  * @author Oliver Frank

  */

 class AsmTypeHelper {

+

+	public static AbstractInsnNode getUnboxingInstructionForType(Type primitiveType) {

+		String objectType = getObjectType(primitiveType);

+		if (objectType == null)

+			return new InsnNode(Opcodes.NOP);

+		return getUnboxingInstructionForType(primitiveType, objectType);

+	}

+

 	public static AbstractInsnNode getUnboxingInstructionForType(Type primitiveType, String objectType) {

 		String methodName = primitiveType.getClassName() + "Value";

 		String desc = Type.getMethodDescriptor(primitiveType, new Type[] {});

diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MoveCodeToCallOrigAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MoveCodeToCallOrigAdapter.java
index 47e1b3f..409d51b 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MoveCodeToCallOrigAdapter.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/MoveCodeToCallOrigAdapter.java
@@ -16,13 +16,19 @@
  **********************************************************************/

 package org.eclipse.objectteams.otredyn.bytecode.asm;

 

+import java.util.ArrayList;

+import java.util.List;

+import java.util.ListIterator;

+

 import org.eclipse.objectteams.otredyn.bytecode.Method;

 import org.eclipse.objectteams.otredyn.transformer.names.ConstantMembers;

 import org.objectweb.asm.Opcodes;

 import org.objectweb.asm.Type;

+import org.objectweb.asm.tree.AbstractInsnNode;

 import org.objectweb.asm.tree.InsnList;

 import org.objectweb.asm.tree.InsnNode;

 import org.objectweb.asm.tree.IntInsnNode;

+import org.objectweb.asm.tree.MethodInsnNode;

 import org.objectweb.asm.tree.MethodNode;

 import org.objectweb.asm.tree.TypeInsnNode;

 

@@ -68,7 +74,14 @@
 		//Unboxing arguments

 		Type[] args = Type.getArgumentTypes(orgMethod.desc);

 		

+		int boundMethodIdSlot = firstArgIndex;

+		

 		if (args.length > 0) {

+			// move boundMethodId to a higher slot, to make lower slots available for original locals

+			newInstructions.add(new IntInsnNode(Opcodes.ILOAD, boundMethodIdSlot));

+			boundMethodIdSlot = callOrig.maxLocals+1;

+			newInstructions.add(new IntInsnNode(Opcodes.ISTORE, boundMethodIdSlot));

+			

 			newInstructions.add(new IntInsnNode(Opcodes.ALOAD, firstArgIndex + argOffset + 1));

 			

 			int slot = firstArgIndex + argOffset;

@@ -91,6 +104,8 @@
 				slot += arg.getSize();

 			}

 		}

+

+		adjustSuperCalls(orgMethod.instructions, orgMethod.name, args, returnType, boundMethodIdSlot);

 		

 		// replace return of the original method with areturn and box the result value if needed

 		replaceReturn(orgMethod.instructions, returnType);

@@ -99,7 +114,7 @@
 		

 		addNewLabelToSwitch(callOrig.instructions, newInstructions, boundMethodId);

 		

-		// a minimum stacksize of 3 is neede to box the arguments

+		// a minimum stacksize of 3 is needed to box the arguments

 		callOrig.maxStack = Math.max(Math.max(callOrig.maxStack, orgMethod.maxStack), 3);

 		

 		// we have to increment the max. stack size, because we have to put NULL on the stack

@@ -109,4 +124,48 @@
 		callOrig.maxLocals = Math.max(callOrig.maxLocals, orgMethod.maxLocals);

 		return true;

 	}

+	

+	/** To avoid infinite recursion, calls super.m(a1, a2) must be translated to super.callOrig(boundMethodId, new Object[] {a1, a2}). */

+	private void adjustSuperCalls(InsnList instructions, String selector, Type[] args, Type returnType, int boundMethodIdSlot) {

+		// search:

+		List<MethodInsnNode> toReplace = new ArrayList<MethodInsnNode>();

+		ListIterator<AbstractInsnNode> orgMethodIter = instructions.iterator();

+		while (orgMethodIter.hasNext()) {

+			AbstractInsnNode orgMethodNode = orgMethodIter.next();

+			if (orgMethodNode.getOpcode() == Opcodes.INVOKESPECIAL && ((MethodInsnNode)orgMethodNode).name.equals(selector))

+				toReplace.add((MethodInsnNode) orgMethodNode);

+		}

+		if (toReplace.isEmpty())

+			return;

+		// replace:

+		for (MethodInsnNode oldNode : toReplace) {

+			// we need to insert into the loading sequence before the invocation, find the insertion points:

+			AbstractInsnNode[] insertionPoints = StackBalanceAnalyzer.findInsertionPointsBefore(oldNode, args);

+			AbstractInsnNode firstInsert = insertionPoints.length > 0 ? insertionPoints[0] : oldNode;

+			

+			// push first arg to _OT$callOrig():

+			instructions.insertBefore(firstInsert, new IntInsnNode(Opcodes.ILOAD, boundMethodIdSlot));

+			

+			// prepare array as second arg to _OT$callOrig():

+			instructions.insertBefore(firstInsert, new IntInsnNode(Opcodes.BIPUSH, args.length));

+			instructions.insertBefore(firstInsert, new TypeInsnNode(Opcodes.ANEWARRAY, "java/lang/Object"));

+			

+			for (int i = 0; i < insertionPoints.length; i++) {

+				// NB: each iteration has an even stack balance, where the top is the Object[].

+				instructions.insertBefore(insertionPoints[i], new InsnNode(Opcodes.DUP));

+				instructions.insertBefore(insertionPoints[i], new IntInsnNode(Opcodes.BIPUSH, i));

+				// leave the original loading sequence in tact and continue at the next point:

+				AbstractInsnNode insertAt = (i +1 < insertionPoints.length) ? insertionPoints[i+1] : oldNode;

+				instructions.insertBefore(insertAt, AsmTypeHelper.getBoxingInstructionForType(args[i]));

+				instructions.insertBefore(insertAt, new InsnNode(Opcodes.AASTORE));

+			}

+

+			if (returnType == Type.VOID_TYPE)

+				instructions.insert(oldNode, new InsnNode(Opcodes.POP));

+			else

+				instructions.insert(oldNode, AsmTypeHelper.getUnboxingInstructionForType(returnType));

+

+			instructions.set(oldNode, new MethodInsnNode(Opcodes.INVOKESPECIAL, ((MethodInsnNode)oldNode).owner, callOrig.getName(), callOrig.getSignature()));

+		}

+	}

 }

diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/StackBalanceAnalyzer.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/StackBalanceAnalyzer.java
new file mode 100644
index 0000000..1c416b8
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/StackBalanceAnalyzer.java
@@ -0,0 +1,87 @@
+/**********************************************************************
+ * This file is part of "Object Teams Dynamic Runtime Environment"
+ * 
+ * Copyright 2014 Stephan Herrmann.
+ * 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ *		Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AbstractInsnNode;
+
+public class StackBalanceAnalyzer {
+
+    /**
+     * Answer an array of insertion points such that each element points to the start of a loading sequence
+     * that produces as many bytes on the stack as are required for the corresponding type in 'args'.
+     * 
+     * @param location point in an instruction list at which all args are present on the stack
+     * @param args types of the arguments on the top of the stack at 'location'
+     * @return one instruction per element in 'args'
+     */
+	public static AbstractInsnNode[] findInsertionPointsBefore(AbstractInsnNode location, Type[] args) {
+		AbstractInsnNode[] nodes = new AbstractInsnNode[args.length];
+		AbstractInsnNode current = location;
+		for (int i = args.length-1; i >= 0; i--) {
+			current = findInsertionPointBefore(current, - args[i].getSize());
+			nodes[args.length-i-1] = current;
+		}
+		return nodes;
+	}
+
+    /**
+     * Answer the closest point in the instruction list before 'location'
+     * where the stack has 'stackDifference' more bytes than at 'location'.
+     * Negative 'stackDifference' means we are looking for smaller stack.
+     * 
+     * @param location start searching here
+     * @param stackDifference 
+     * @return the last instruction before which the required stack size was present 
+     */
+    public static AbstractInsnNode findInsertionPointBefore(AbstractInsnNode location, int stackDifference) {
+    	int offset = 0;    	
+    	AbstractInsnNode current = location;
+    	while (offset != stackDifference) {
+    		current = location.getPrevious();
+    		if (current == null)
+    			return null;
+    		offset -= SIZE[current.getOpcode()];
+    	}
+    	return current;
+    }
+
+	
+	// Field from org.objectweb.asm.Frame, made accessible:
+    /**
+     * The stack size variation corresponding to each JVM instruction. This
+     * stack variation is equal to the size of the values produced by an
+     * instruction, minus the size of the values consumed by this instruction.
+     */
+    static final int[] SIZE;
+
+    /**
+     * Computes the stack size variation corresponding to each JVM instruction.
+     */
+    static {
+        int i;
+        int[] b = new int[202];
+        String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD"
+                + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD"
+                + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED"
+                + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
+        for (i = 0; i < b.length; ++i) {
+            b[i] = s.charAt(i) - 'E';
+        }
+        SIZE = b;
+    }
+    
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/otreAgent.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/otreAgent.java
index 48ec34d..61f5d28 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/otreAgent.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/otreAgent.java
@@ -17,6 +17,10 @@
 
 import java.lang.instrument.Instrumentation;
 
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.commons.AdviceAdapter;
+import org.objectweb.asm.tree.InsnNode;
+
 
 /**
  * @author  Christine Hundt
@@ -29,11 +33,17 @@
 
 	public static void premain(String options, Instrumentation inst) {
 		instCopy = inst;
-
+		checkASM();
 		otTransformer = new ObjectTeamsTransformer();
 		instCopy.addTransformer(otTransformer);
 	}
 	
+	private static void checkASM() {
+		ClassVisitor.class.getName(); // asm
+		AdviceAdapter.class.getName(); // asm.commons
+		InsnNode.class.getName(); // asm.tree
+	}
+
 	public static Instrumentation getInstrumentation() {
 		return instCopy;
 	}
diff --git a/plugins/org.eclipse.objectteams.runtime/src/org/eclipse/objectteams/otredyn/runtime/IBoundClass.java b/plugins/org.eclipse.objectteams.runtime/src/org/eclipse/objectteams/otredyn/runtime/IBoundClass.java
index 3e7ee52..c09aaff 100644
--- a/plugins/org.eclipse.objectteams.runtime/src/org/eclipse/objectteams/otredyn/runtime/IBoundClass.java
+++ b/plugins/org.eclipse.objectteams.runtime/src/org/eclipse/objectteams/otredyn/runtime/IBoundClass.java
@@ -15,6 +15,8 @@
  **********************************************************************/
 package org.eclipse.objectteams.otredyn.runtime;
 
+import java.util.List;
+
 /**
  * Interface through which the {@link TeamManager} reaches into the OTREDyn.
  * Representation of a class that participates in a binding.
@@ -81,4 +83,9 @@
 	 */
 	void addWiringTask(ISubclassWiringTask subclassWiringTask);
 
+	/**
+	 * Assuming this instance represents a role, answer all tsub roles in any teams known at this point.
+	 */
+	List<IBoundClass> getTSubsOfThis(IClassRepository classRepository, IClassIdentifierProvider idProvider);
+
 }
diff --git a/plugins/org.eclipse.objectteams.runtime/src/org/eclipse/objectteams/otredyn/runtime/TeamManager.java b/plugins/org.eclipse.objectteams.runtime/src/org/eclipse/objectteams/otredyn/runtime/TeamManager.java
index fb69891..df63479 100644
--- a/plugins/org.eclipse.objectteams.runtime/src/org/eclipse/objectteams/otredyn/runtime/TeamManager.java
+++ b/plugins/org.eclipse.objectteams.runtime/src/org/eclipse/objectteams/otredyn/runtime/TeamManager.java
@@ -115,7 +115,16 @@
 	 * @return
 	 */
 	public static int getMemberId(int accessId, Class<? extends ITeam> teamClass) {
-		Integer id = accessIdMap.get(teamClass).get(accessId);
+		List<Integer> teamMap = accessIdMap.get(teamClass);
+		if (teamMap == null) {
+			// TODO: is it safe to assume that the accessId is the same between sub & super teams?
+			Class<?> superClass = teamClass.getSuperclass();
+			if (ITeam.class.isAssignableFrom(superClass)) {
+				@SuppressWarnings("unchecked") Class<? extends ITeam> superTeam = (Class<? extends ITeam>) superClass;
+				return getMemberId(accessId, superTeam);
+			}
+		}
+		Integer id = teamMap.get(accessId);
 		return id;
 	}
 
@@ -172,25 +181,33 @@
 			String boundClassIdentifier = provider.getBoundClassIdentifier(teamClass, boundClassName);
 			// FIXME(SH): the following may need adaptation for OT/Equinox or other multi-classloader settings:
 			IBoundClass boundClass = classRepository.getBoundClass(boundClassName.replace('/', '.'), boundClassIdentifier, teamClass.getClassLoader());
-			// FIXME(SH): if boundClass is a role we need to find tsub roles, too!
 			switch (binding.getType()) {
 			case CALLIN_BINDING:
-				IMethod method = boundClass.getMethod(binding.getMemberName(), binding.getMemberSignature(), binding.getBaseFlags(), binding.isHandleCovariantReturn());
-				int joinpointId = getJoinpointId(boundClass
-						.getMethodIdentifier(method));
-				synchronized (method) {
-					changeTeamsForJoinpoint(t, binding.getPerTeamId(), joinpointId, stateChange);
-					List<Integer> subJoinpoints = joinpointToSubJoinpoints.get(joinpointId);
-					if (subJoinpoints != null)
-						for (Integer subJoinpoint : subJoinpoints)
-							changeTeamsForJoinpoint(t, binding.getPerTeamId(), subJoinpoint, stateChange);
-				}
-				boundClass.handleAddingOfBinding(binding); // TODO: do we want/need to group all bindings into one action?
+				handleBindingForBase(t, stateChange, binding, boundClass, provider);
 				break;
-				//$CASES-OMITTED$ // TODO: this marker-comment has not effect?
+			default:
+				// no further action for *ACCESS bindings
 			}
 		}
 	}
+
+	private void handleBindingForBase(ITeam t, ITeamManager.TeamStateChange stateChange, IBinding binding, IBoundClass boundClass, IClassIdentifierProvider provider) {
+		IMethod method = boundClass.getMethod(binding.getMemberName(), binding.getMemberSignature(), binding.getBaseFlags(), binding.isHandleCovariantReturn());
+		int joinpointId = getJoinpointId(boundClass
+				.getMethodIdentifier(method));
+		synchronized (method) {
+			changeTeamsForJoinpoint(t, binding.getPerTeamId(), joinpointId, stateChange);
+			List<Integer> subJoinpoints = joinpointToSubJoinpoints.get(joinpointId);
+			if (subJoinpoints != null)
+				for (Integer subJoinpoint : subJoinpoints)
+					changeTeamsForJoinpoint(t, binding.getPerTeamId(), subJoinpoint, stateChange);
+		}
+		boundClass.handleAddingOfBinding(binding); // TODO: do we want/need to group all bindings into one action?
+
+		for (IBoundClass tsubBase : boundClass.getTSubsOfThis(classRepository, provider)) {
+			handleBindingForBase(t, stateChange, binding, tsubBase, provider);
+		}
+	}
 	
 	/**
 	 * When a team is about to be activated propagate its bindings to all base classes,
@@ -208,13 +225,19 @@
 			String boundClassIdentifier = provider.getBoundClassIdentifier(teamClass, boundClassName);
 			// FIXME(SH): the following may need adaptation for OT/Equinox or other multi-classloader settings:
 			IBoundClass boundClass = classRepository.getBoundClass(boundClassName.replace('/', '.'), boundClassIdentifier, teamClass.getClassLoader());
-			// FIXME(SH): if boundClass is a role we need to find tsub roles, too!
 			switch (binding.getType()) {
 			case CALLIN_BINDING:
-				boundClass.handleAddingOfBinding(binding);
+				prepareBindingForBase(binding, boundClass, provider);
 				break;
+			default: // no further action for *ACCESS bindings
 			}
-		}		
+		}
+	}
+
+	private static void prepareBindingForBase(IBinding binding, IBoundClass boundClass, IClassIdentifierProvider idProvider) {
+		boundClass.handleAddingOfBinding(binding);
+		for (IBoundClass tsubBase : boundClass.getTSubsOfThis(classRepository, idProvider))
+			prepareBindingForBase(binding, tsubBase, idProvider);
 	}
 
 	public static void handleTeamLoaded(Class<? extends ITeam> teamClass) {
@@ -250,6 +273,7 @@
 				}
 				boundClass.handleAddingOfBinding(binding);
 				break;
+			default: // no action for CALLIN_BINDING here
 			}
 		}
 	}
@@ -355,8 +379,11 @@
 			teams.add(d, srcTeams.get(s));
 			callinIds.add(0, srcCallins.get(s));
 		}
-		_teams.set(destJoinpointId, teams);
-		_callinIds.set(destJoinpointId, callinIds);
+		// transitively pass the new information down the tree of subJoinpoints:
+		List<Integer> destDests = joinpointToSubJoinpoints.get(destJoinpointId);
+		if (destDests != null && !destDests.isEmpty())
+			for (Integer destDest : destDests)
+				applyJoinpointMerge(destJoinpointId, destDest);
 	}
 	
 	/** 
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/AbstractOTJLDNullAnnotationTest.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/AbstractOTJLDNullAnnotationTest.java
new file mode 100644
index 0000000..6c45705
--- /dev/null
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/AbstractOTJLDNullAnnotationTest.java
@@ -0,0 +1,381 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2014 Stephan Herrmann
+ * 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * 	  Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otdt.tests.otjld;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Map;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jdt.core.tests.compiler.regression.AbstractNullAnnotationTest;
+import org.eclipse.jdt.core.tests.compiler.regression.InMemoryNameEnvironment;
+import org.eclipse.jdt.core.tests.compiler.regression.RegressionTestSetup;
+import org.eclipse.jdt.core.tests.compiler.regression.Requestor;
+import org.eclipse.jdt.core.tests.util.CompilerTestSetup;
+import org.eclipse.jdt.core.tests.util.TestVerifier;
+import org.eclipse.jdt.core.tests.util.Util;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.batch.FileSystem;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.objectteams.otdt.core.ext.WeavingScheme;
+import org.eclipse.objectteams.otdt.tests.ClasspathUtil;
+
+/**
+ * Common super class for OT-tests with null annotations (mostly copied from AbstractOTJLDTest).
+ */
+public class AbstractOTJLDNullAnnotationTest extends AbstractNullAnnotationTest {
+
+	/** a test verifier that allows reusing a running vm even in the presence of (constant) vm arguments. */
+	protected class OTTestVerifier extends TestVerifier {
+		protected OTTestVerifier(boolean reuseVM) {
+			super(reuseVM);
+			this.fVMArguments = getOTVMArgs();
+		}
+		@Override
+		public boolean verifyClassFiles(String sourceFilePath, String className, String expectedOutputString, String expectedErrorStringStart, 
+										String[] classpaths, String[] programArguments, String[] vmArguments) {
+			vmArguments = mergeArgs(vmArguments);
+			return super.verifyClassFiles(sourceFilePath, className, expectedOutputString, expectedErrorStringStart, classpaths, programArguments, vmArguments);
+		}
+		@Override
+		public boolean vmArgsEqual(String[] newArgs) {
+			return super.vmArgsEqual(mergeArgs(newArgs));
+		}
+		protected String[] mergeArgs(String[] newArgs) {
+			String[] OTVMArgs = getOTVMArgs();
+			if (newArgs == null)
+				return OTVMArgs;
+			else {
+				int l1 = OTVMArgs.length;
+				int l2 = newArgs.length;
+				String[] result = new String[l1+l2];
+				System.arraycopy(OTVMArgs, 0, result, 0, l1);
+				System.arraycopy(newArgs, 0, result, l1, l2);
+				return result;
+			}
+		}
+	}
+	
+	private static String getOTDTJarPath(String jarName) {
+		return ClasspathUtil.OTDT_PATH + File.separator + "lib" + File.separator + jarName + ".jar";
+	}
+	
+	public String[] getOTVMArgs() {
+		String OTRE_MIN_JAR_PATH, OTAGENT_JAR_PATH;
+		OTRE_MIN_JAR_PATH 		= getOTDTJarPath("otre_min");
+		switch (this.weavingScheme) {
+		case OTDRE:
+			OTAGENT_JAR_PATH  		= getOTDTJarPath("otredyn_agent");
+			break;
+		case OTRE:
+			OTAGENT_JAR_PATH  		= getOTDTJarPath("otre_agent");
+			break;
+		default:
+			throw new IllegalStateException("Unsupported weavingScheme "+this.weavingScheme);
+		}
+		return new String[] {
+				"-javaagent:"+OTAGENT_JAR_PATH,
+				"-Xbootclasspath/a:"+OTRE_MIN_JAR_PATH,
+				"-Dot.dump=1"
+		};
+	}
+	
+	public static boolean IS_JRE_8;
+	static {
+		String javaVersion = System.getProperty("java.specification.version");
+		IS_JRE_8 = "1.8".equals(javaVersion);
+	}
+	protected String foreach(String elemType) {
+		return (IS_JRE_8 && this.complianceLevel < ClassFileConstants.JDK1_8) 
+				? "public void forEach(java.util.function.Consumer<? super "+elemType+"> element) {}\n"
+				: "";
+	}
+	protected String spliterator(String elemType) {
+		return (IS_JRE_8 && this.complianceLevel < ClassFileConstants.JDK1_8) 
+				? "public java.util.Spliterator<"+elemType+"> spliterator() { return null; }\n"
+				: "";
+	}
+	protected String spliteratorCallout() {
+		return (IS_JRE_8 && this.complianceLevel < ClassFileConstants.JDK1_8) ? "spliterator -> spliterator;\n" : "";
+	}
+	// ===
+	
+	protected static final JavacTestOptions DEFAULT_TEST_OPTIONS = new JavacTestOptions();
+
+	// shall compiler output be matched exactly or using some matching?
+	boolean errorMatching = false;
+	
+	// each subarray defines a set of classes to be compiled together:
+	protected String[][] compileOrder;
+	
+	protected WeavingScheme weavingScheme = WeavingScheme.OTRE;
+	
+	public AbstractOTJLDNullAnnotationTest(String name) {
+		super(name);
+	}
+
+	/** Add otre/otdre and (bcel or asm) to the class path. */
+	@Override
+	protected String[] getDefaultClassPaths() {
+		String[] defaults = super.getDefaultClassPaths();
+		int len = defaults.length;
+		IPath[] bytecodeLibJarPath = ClasspathUtil.getWeaverPaths(this.weavingScheme);
+		int len2 = bytecodeLibJarPath.length;
+		System.arraycopy(defaults, 0, defaults=new String[len+1+len2], 0, len);
+		defaults[len] = new Path(ClasspathUtil.getOTREPath(this.weavingScheme)).toString();
+		for (int i=0; i<len2; i++)
+			defaults[len+1+i] = bytecodeLibJarPath[i].toString();
+		return defaults;
+	}
+
+	@Override
+	public void initialize(CompilerTestSetup setUp) {
+		super.initialize(setUp);
+		if ("dynamic".equals(System.getProperty("ot.weaving"))
+				||"otdre".equals(System.getProperty("test.ot.weaving")))
+			weavingScheme = WeavingScheme.OTDRE;
+		if (setUp instanceof RegressionTestSetup) {
+			RegressionTestSetup regressionSetTup = (RegressionTestSetup) setUp;
+			if (!(regressionSetTup.verifier instanceof OTTestVerifier)) {
+				// overwrite plain TestVerifier:
+				regressionSetTup.verifier = this.verifier = new OTTestVerifier(true/*reuseVM*/);
+			}
+		}
+	}
+
+	@Override
+	protected TestVerifier getTestVerifier(boolean reuseVM) {
+		return new OTTestVerifier(reuseVM);
+	}
+	
+	@Override
+	protected void tearDown() throws Exception {
+		this.compileOrder = null;
+		super.tearDown();
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	protected Map getCompilerOptions() {
+		Map options = super.getCompilerOptions();
+		options.put(CompilerOptions.OPTION_ReportUnnecessaryElse, CompilerOptions.IGNORE);
+		options.put(CompilerOptions.OPTION_ReportSyntheticAccessEmulation, CompilerOptions.IGNORE);
+		options.put(CompilerOptions.OPTION_ReportUnusedWarningToken, CompilerOptions.ERROR);
+		options.put(CompilerOptions.OPTION_WeavingScheme, this.weavingScheme.toString());
+		// FIXME: consider setting to warning:
+		options.put(CompilerOptions.OPTION_ReportOtreWeavingIntoJava8, CompilerOptions.IGNORE);
+		return options;
+	}
+	
+	protected void runNegativeTestMatching(String[] testFiles, String expectedCompilerLog) {
+		this.errorMatching = true;
+		runTest(
+		 		// test directory preparation
+				true /* flush output directory */,
+				testFiles /* test files */,
+				// compiler options
+				null /* no class libraries */,
+				null /* no custom options */,
+				false /* do not perform statements recovery */,
+				null /* no custom requestor */,
+				// compiler results
+				true /* expecting compiler errors */,
+				expectedCompilerLog /* expected compiler log */,
+				// runtime options
+				false /* do not force execution */,
+				null /* no vm arguments */,
+				// runtime results
+				null /* do not check output string */,
+				null /* do not check error string */,
+				// javac options
+				DEFAULT_TEST_OPTIONS /* javac test options */);
+		this.errorMatching = false;
+	}
+
+	// inaccessible helper from super
+	void logTestFiles(boolean logTitle, String[] testFiles) {
+		if (logTitle) {
+			logTestTitle();
+		}
+		for (int i = 0; i < testFiles.length; i += 2) {
+			System.out.print(testFiles[i]);
+			System.out.println(" ["); //$NON-NLS-1$
+			System.out.println(testFiles[i + 1]);
+			System.out.println("]"); //$NON-NLS-1$
+		}
+	}
+	// inaccessible helper from super
+	void logTestTitle() {
+		System.out.println(getClass().getName() + '#' + getName());
+	}
+	
+	// support explicit compile order in several steps:
+	@Override
+	protected void compileTestFiles(Compiler batchCompiler, String[] testFiles) {
+		if (this.compileOrder == null) {
+			super.compileTestFiles(batchCompiler, testFiles);
+		} else {
+			for (String[] bunch : this.compileOrder) {
+				String[] bunchFiles = new String[bunch.length * 2];
+				int b = 0;
+				for (int i = 0; i < bunch.length; i++) {
+					int b0 = b;
+					for (int j = 0; j < testFiles.length; j+=2) {
+						if (bunch[i].equals(testFiles[j])) {
+							bunchFiles[b++] = testFiles[j];
+							bunchFiles[b++] = testFiles[j+1];
+						}
+					}
+					assertTrue("Unmatched filename: "+bunch[i], b == b0+2);
+				}
+				super.compileTestFiles(batchCompiler, bunchFiles);
+				batchCompiler.lookupEnvironment.nameEnvironment.cleanup(); // don't use chached info from previous runs
+			}
+		}
+	}
+	
+	protected INameEnvironment getNameEnvironment(final String[] testFiles, String[] classPaths) {
+		this.classpaths = classPaths == null ? getDefaultClassPaths() : classPaths;
+		// make cleanup weaker:
+		return new InMemoryNameEnvironment(testFiles, getClassLibs(false)) {
+			@Override
+			public void cleanup() {
+				for (int i = 0, max = this.classLibs.length; i < max; i++)
+					if (this.classLibs[i] instanceof FileSystem)
+						((FileSystem) this.classLibs[i]).softReset();
+			}
+		};
+	}
+	
+	/** Additional entry for tests expecting a compiler warning and don't run. */
+	protected void runTestExpectingWarnings(String[] files, String expectedWarnings) {
+    	Map options = getCompilerOptions();
+		runConformTest(
+	 		// test directory preparation
+			true /* flush output directory */,
+			files,
+			// compiler options
+			null /* no class libraries */,
+			options /* custom options - happen to be the default not changed by the test suite */,
+			// compiler results
+			expectedWarnings,
+			// runtime results
+			null /* do not check output string */,
+			null /* do not check error string */,
+			// javac options
+			JavacTestOptions.Excuse.EclipseHasSomeMoreWarnings /* javac test options */);	
+	}
+	
+	/** Additional entry for tests expecting a compiler warning and don't run. */
+	protected void runTestExpectingWarnings(String[] files, String expectedWarnings, Map options) {
+		runConformTest(
+	 		// test directory preparation
+			true /* flush output directory */,
+			files,
+			// compiler options
+			null /* no class libraries */,
+			options /* custom options - happen to be the default not changed by the test suite */,
+			// compiler results
+			expectedWarnings,
+			// runtime results
+			null /* do not check output string */,
+			null /* do not check error string */,
+			// javac options
+			JavacTestOptions.Excuse.EclipseHasSomeMoreWarnings /* javac test options */);	
+	}
+	
+	/** Additional entry for tests expecting a compiler warning and don't run. */
+	protected void runTestExpectingWarnings(String[] files, String expectedWarnings, boolean flushOutputDirectory) {
+    	Map options = getCompilerOptions();
+		runConformTest(
+	 		// test directory preparation
+			flushOutputDirectory,
+			files,
+			// compiler options
+			null /* no class libraries */,
+			options /* custom options - happen to be the default not changed by the test suite */,
+			// compiler results
+			expectedWarnings,
+			// runtime results
+			null /* do not check output string */,
+			null /* do not check error string */,
+			// javac options
+			JavacTestOptions.Excuse.EclipseHasSomeMoreWarnings /* javac test options */);	
+	}
+	/** Additional entry for tests expecting a compiler warning and run. */
+	protected void runTestExpectingWarnings(String[] files, String expectedWarnings, String expectedOutput) {
+    	Map options = getCompilerOptions();
+		runConformTest(
+	 		// test directory preparation
+			true/*flushOutputDirectory*/,
+			files,
+			// compiler options
+			null /* no class libraries */,
+			options /* custom options - happen to be the default not changed by the test suite */,
+			// compiler results
+			expectedWarnings,
+			// runtime results
+			expectedOutput,
+			null /* do not check error string */,
+			// javac options
+			JavacTestOptions.Excuse.EclipseHasSomeMoreWarnings /* javac test options */);	
+	}
+
+	protected void myWriteFiles(String[] testFiles) {
+		// force the directory to comply with the infrastructure from AbstractRegressionTest:
+		String testName = null;
+		try {
+			testName = getName();
+			setName("regression");
+			// Write files in dir
+			writeFiles(testFiles);
+		} finally {
+			setName(testName);
+		}
+	}
+	
+	protected String getTestResourcePath(String filename) {
+        try
+        {
+            URL platformURL = Platform
+				                .getBundle("org.eclipse.objectteams.otdt.tests")
+				                .getEntry("/testresources/"+filename);
+            return new File(FileLocator.toFileURL(platformURL).getFile())
+                .getAbsolutePath();
+        }
+        catch (IOException ex)
+        {
+            ex.printStackTrace();
+        }
+        return null;
+	}
+	/** Create a vm arg for team activation and reset the verifier (avoid reuse of a running VM). */
+	protected String[] getTeamActivationVMArgs(String relativeFilePath) {
+		if (this.verifier != null)
+			this.verifier.shutDown();
+        this.verifier = getTestVerifier(false);
+        this.createdVerifier = true;
+		return new String[] {
+				"-Dot.teamconfig="+OUTPUT_DIR+'/'+relativeFilePath
+		};
+	}
+}
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/AllTests.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/AllTests.java
index 9bfe2c8..c4c8328 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/AllTests.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/AllTests.java
@@ -39,6 +39,7 @@
 import org.eclipse.objectteams.otdt.tests.otjld.other.Java8;
 import org.eclipse.objectteams.otdt.tests.otjld.other.Misc;
 import org.eclipse.objectteams.otdt.tests.otjld.other.Modifiers;
+import org.eclipse.objectteams.otdt.tests.otjld.other.OTNullTypeAnnotationTest;
 import org.eclipse.objectteams.otdt.tests.otjld.regression.CompilationOrder;
 import org.eclipse.objectteams.otdt.tests.otjld.regression.ComplexStructures;
 import org.eclipse.objectteams.otdt.tests.otjld.regression.DevelopmentExamples;
@@ -135,6 +136,7 @@
 		/*A.1*/addComplianceSuite(suite, Java5.testClass());
 		/*A.2*/addComplianceSuite(suite, Java7.testClass(), AbstractCompilerTest.F_1_7);
 		/*---*/addComplianceSuite(suite, Java8.testClass(), AbstractCompilerTest.F_1_8);
+		/*---*/addComplianceSuite(suite, OTNullTypeAnnotationTest.testClass(), AbstractCompilerTest.F_1_8);
 		/*0.m*/addComplianceSuite(suite, Misc.testClass());
 		
 		// regression:
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java
index 9c6df41..993dd47 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java
@@ -1322,22 +1322,22 @@
     public void testA12_genericRoleFeature16a() {
     	runConformTest(
     		new String[] {
-    	"TeamA12grf16_3.java",
-    			"public team class TeamA12grf16_3 extends TeamA12grf16_2<String> {\n" +
+    	"TeamA12grf16a_3.java",
+    			"public team class TeamA12grf16a_3 extends TeamA12grf16a_2<String> {\n" +
 				"   @Override\n" +
-				"	public class R playedBy TA12grf16 {\n" +
+				"	public class R playedBy TA12grf16a {\n" +
 				"		 test <- before test;\n" +
 				"   }\n" +
     			"   public static void main(String... args) {\n" +
-    			"       new TeamA12grf16_3().activate();\n" +
-    			"       System.out.print(new TA12grf16().test(\"K\"));" +
+    			"       new TeamA12grf16a_3().activate();\n" +
+    			"       System.out.print(new TA12grf16a().test(\"K\"));" +
     			"   }\n" +
     			"}\n",
-    	"TeamA12grf16_2.java",
-				"public team class TeamA12grf16_2<U> extends TeamA12grf16_1<U> {\n" +
+    	"TeamA12grf16a_2.java",
+				"public team class TeamA12grf16a_2<U> extends TeamA12grf16a_1<U> {\n" +
 				"}\n",
-    	"TeamA12grf16_1.java",
-    			"public team class TeamA12grf16_1<U> {\n" +
+    	"TeamA12grf16a_1.java",
+    			"public team class TeamA12grf16a_1<U> {\n" +
     			"	public class R {\n" +
 				"        private U test(U u) {\n" +
 				"            System.out.print(\"O\");\n" +
@@ -1345,8 +1345,8 @@
 				"        }\n" +
     			"   }\n" +
     			"}\n",
-    	"TA12grf16.java",
-    			"public class TA12grf16 {\n" +
+    	"TA12grf16a.java",
+    			"public class TA12grf16a {\n" +
     			"   protected String test(String u){ return u;}" +
     			"}\n"
     		},
@@ -1359,40 +1359,40 @@
     public void testA12_genericRoleFeature16f() {
     	runNegativeTest(
     		new String[] {
-    	"TeamA12grf16_3.java",
-    			"public team class TeamA12grf16_3 extends TeamA12grf16_2<String> {\n" +
+    	"TeamA12grf16f_3.java",
+    			"public team class TeamA12grf16f_3 extends TeamA12grf16f_2<String> {\n" +
     			"   public static void main(String... args) {\n" +
-    			"       new TeamA12grf16_3().activate();\n" +
-    			"       System.out.print(new TA12grf16().test(\"K\"));" +
+    			"       new TeamA12grf16f_3().activate();\n" +
+    			"       System.out.print(new TA12grf16f().test(\"K\"));" +
     			"   }\n" +
     			"}\n",
-    	"TeamA12grf16_2.java",
-				"public team class TeamA12grf16_2<U> extends TeamA12grf16_1<U> {\n" +
+    	"TeamA12grf16f_2.java",
+				"public team class TeamA12grf16f_2<U> extends TeamA12grf16f_1<U> {\n" +
 				"   @Override\n" +
-				"	public class R playedBy TA12grf16 {\n" +
+				"	public class R playedBy TA12grf16f {\n" +
 				"		 test <- before test;\n" +
 				"   }\n" +
 				"}\n",
-    	"TeamA12grf16_1.java",
-    			"public team class TeamA12grf16_1<U> {\n" +
+    	"TeamA12grf16f_1.java",
+    			"public team class TeamA12grf16f_1<U> {\n" +
     			"	public class R {\n" +
 				"        private U test(U u) {\n" +
 				"            return u;\n" +
 				"        }\n" +
     			"   }\n" +
     			"}\n",
-    	"TA12grf16.java",
-    			"public class TA12grf16 {\n" +
+    	"TA12grf16f.java",
+    			"public class TA12grf16f {\n" +
     			"   protected String test(String u){ return u;}" +
     			"}\n"
     		},
     		"----------\n" + 
-			"1. ERROR in TeamA12grf16_2.java (at line 4)\n" + 
+			"1. ERROR in TeamA12grf16f_2.java (at line 4)\n" + 
 			"	test <- before test;\n" + 
 			"	^^^^\n" + 
 			(this.weavingScheme == WeavingScheme.OTRE
 			? "Type mismatch: cannot convert from String to U\n"
-			: "The method test(U) in the type TeamA12grf16_2<U>.R is not applicable for the arguments (String)\n"
+			: "The method test(U) in the type TeamA12grf16f_2<U>.R is not applicable for the arguments (String)\n"
 			) +
 			"----------\n");
     }
@@ -1457,7 +1457,7 @@
     		"OK",
     		null,
     		false/*shouldFlushOutputDirectory*/,
-    		null);
+    		new String[] {"-DA12grf18_2=2"}); // force new vm launch to accept the new class version
     }
 
     // a role does not use the type parameter of its enclosing team, has callin binding, copied as phantom role
@@ -1496,7 +1496,7 @@
     		"OK",
     		null,
     		false/*shouldFlushOutputDirectory*/,
-    		null);
+    		new String[] {"-DA12grf19_2=2"}); // force new vm launch to accept the new class version
     }
 
     // a parameter of a callout binding requires autoboxing - explicit mapping
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java8.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java8.java
index 8a43d15..ab5cd0e 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java8.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java8.java
@@ -264,7 +264,7 @@
 			"	public class R {}\n" +
 			"}\n",
 		"C1.java",
-			"public abstract class C1 {\n" +
+			"public abstract team class C1 {\n" +
 			"	final T1 t = new T1();\n" +
 			"	abstract void test1(final C1 a, R<@a.t> c);\n" +
 			"	abstract void test2(final Object o, C2<java.lang.@p1.Marker Object> c);\n" + // bug, should be java.lang. @p1.Marker Object
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/OTNullTypeAnnotationTest.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/OTNullTypeAnnotationTest.java
new file mode 100644
index 0000000..b4dd521
--- /dev/null
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/OTNullTypeAnnotationTest.java
@@ -0,0 +1,188 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ *
+ * Copyright 2014 Stephan Herrmann
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ *
+ * Contributors:
+ * 	  Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otdt.tests.otjld.other;
+
+import junit.framework.Test;
+
+import org.eclipse.jdt.core.tests.util.CompilerTestSetup;
+import org.eclipse.objectteams.otdt.core.ext.WeavingScheme;
+import org.eclipse.objectteams.otdt.tests.otjld.AbstractOTJLDNullAnnotationTest;
+
+/** Test combination of OT-types with null type annotations. */
+public class OTNullTypeAnnotationTest extends AbstractOTJLDNullAnnotationTest {
+	
+	public OTNullTypeAnnotationTest(String name) {
+		super(name);
+	}
+
+	// Static initializer to specify tests subset using TESTS_* static variables
+	// All specified tests which do not belong to the class are skipped...
+	static {
+//			TESTS_NAMES = new String[] { "testExplicitTeamAnchor1" };
+//			TESTS_NUMBERS = new int[] { 561 };
+//			TESTS_RANGE = new int[] { 1, 2049 };
+	}
+
+	public static Test suite() {
+		return buildMinimalComplianceTestSuite(testClass(), F_1_8);
+	}
+
+	public static Class testClass() {
+		return OTNullTypeAnnotationTest.class;
+	}
+	
+	@Override
+	public void initialize(CompilerTestSetup setUp) {
+		super.initialize(setUp);
+		if (this.weavingScheme == WeavingScheme.OTRE)
+			System.err.println("Running Java8 tests for OTRE weaver will skip most tests");
+	}
+
+	// Bug 437767 - [java8][null] semantically integrate null type annotations with anchored role types 
+	// see comment 1
+	public void testImplicitTeamAnchor1() {
+		if (this.weavingScheme == WeavingScheme.OTRE) return;
+		runConformTestWithLibs(
+			new String[] {
+				"MyTeam.java",
+				"import org.eclipse.jdt.annotation.*;\n" +
+				"import java.util.*;\n" +
+				"public team class MyTeam {\n" +
+				"	protected class MyRole {\n" +
+				"		protected void print() {}\n" +
+				"	}\n" +
+				"	void test() {\n" + 
+				"		List<@NonNull MyRole> someRoles = new ArrayList<>();\n" + 
+				"		@NonNull MyRole role = someRoles.get(0);\n" + 
+				"		role.print();\n" + 
+				"	}\n" +
+				"}\n"
+			},
+			getCompilerOptions(),
+			"");
+	}
+
+	public void testImplicitTeamAnchor2() {
+		if (this.weavingScheme == WeavingScheme.OTRE) return;
+		runNegativeTestWithLibs(
+			new String[] {
+				"MyTeam.java",
+				"import org.eclipse.jdt.annotation.*;\n" +
+				"import java.util.*;\n" +
+				"public team class MyTeam {\n" +
+				"	protected class MyRole {\n" +
+				"		protected void print() {}\n" +
+				"	}\n" +
+				"	void test() {\n" + 
+				"		List<@Nullable MyRole> someRoles = new ArrayList<>();\n" + 
+				"		@NonNull MyRole role = someRoles.get(0);\n" + 
+				"		role.print();\n" + 
+				"	}\n" +
+				"}\n"
+			},
+			getCompilerOptions(),
+			"----------\n" + 
+			"1. ERROR in MyTeam.java (at line 9)\n" + 
+			"	@NonNull MyRole role = someRoles.get(0);\n" + 
+			"	                       ^^^^^^^^^^^^^^^^\n" + 
+			"Null type mismatch (type annotations): required \'MyTeam.@NonNull MyRole\' but this expression has type \'MyTeam.@Nullable MyRole\'\n" + 
+			"----------\n");
+	}
+
+	public void testExplicitTeamAnchor1() {
+		if (this.weavingScheme == WeavingScheme.OTRE) return;
+		runNegativeTestWithLibs(
+			new String[] {
+				"Main.java",
+				"import org.eclipse.jdt.annotation.*;\n" +
+				"import java.util.*;\n" +
+				"public class Main {\n" +
+				"	void test(final MyTeam t, List<@Nullable MyRole<@t>> someRoles) {\n" +
+				"		@NonNull MyRole<@t> role = someRoles.get(0);\n" + 
+				"		role.print();\n" + 
+				"	}\n" +
+				"}\n",
+				"MyTeam.java",
+				"public team class MyTeam {\n" +
+				"	public class MyRole {\n" +
+				"		public void print() {}\n" +
+				"	}\n" +
+				"}\n"
+			},
+			getCompilerOptions(),
+			"----------\n" + 
+			"1. ERROR in Main.java (at line 5)\n" + 
+			"	@NonNull MyRole<@t> role = someRoles.get(0);\n" + 
+			"	                           ^^^^^^^^^^^^^^^^\n" + 
+			"Null type mismatch (type annotations): required \'MyTeam.@NonNull MyRole\' but this expression has type \'MyTeam.@Nullable MyRole\'\n" + 
+			"----------\n");
+	}
+
+	public void testLiftingType1() {
+		if (this.weavingScheme == WeavingScheme.OTRE) return;
+		runNegativeTestWithLibs(
+			new String[] {
+				"MyTeam.java",
+				"import org.eclipse.jdt.annotation.*;\n" +
+				"public team class MyTeam {\n" +
+				"	protected class MyRole playedBy MyBase {\n" +
+				"		protected void print() {}\n" +
+				"	}\n" +
+				"	void test(@Nullable MyBase as @NonNull MyRole r) {}\n" +
+				"}\n",
+				"MyBase.java",
+				"public class MyBase {}\n"
+			},
+			getCompilerOptions(),
+			"----------\n" + 
+			"1. ERROR in MyTeam.java (at line 6)\n" + 
+			"	void test(@Nullable MyBase as @NonNull MyRole r) {}\n" + 
+			"	                    ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Null type mismatch (type annotations): required \'MyTeam.@NonNull MyRole\' but this expression has type \'@Nullable MyBase\'\n" + 
+			"----------\n");
+	}
+
+	public void testLiftingType2() {
+		if (this.weavingScheme == WeavingScheme.OTRE) return;
+		runNegativeTestWithLibs(
+			new String[] {
+				"MyTeam.java",
+				"import org.eclipse.jdt.annotation.*;\n" +
+				"public team class MyTeam {\n" +
+				"	protected class MyRole playedBy MyBase {\n" +
+				"		protected void print() {}\n" +
+				"	}\n" +
+				"	void test1(MyBase @Nullable[] as MyRole @NonNull[] r) {}\n" +
+				"	void test2(@Nullable MyBase @NonNull[] as @NonNull MyRole @NonNull[] r) {}\n" +
+				"}\n",
+				"MyBase.java",
+				"public class MyBase {}\n"
+			},
+			getCompilerOptions(),
+			"----------\n" + 
+			"1. ERROR in MyTeam.java (at line 6)\n" + 
+			"	void test1(MyBase @Nullable[] as MyRole @NonNull[] r) {}\n" + 
+			"	           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Null type mismatch (type annotations): required \'MyTeam.MyRole @NonNull[]\' but this expression has type \'MyBase @Nullable[]\'\n" + 
+			"----------\n" + 
+			"2. ERROR in MyTeam.java (at line 7)\n" + 
+			"	void test2(@Nullable MyBase @NonNull[] as @NonNull MyRole @NonNull[] r) {}\n" + 
+			"	                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Null type mismatch (type annotations): required \'MyTeam.@NonNull MyRole @NonNull[]\' but this expression has type \'@Nullable MyBase @NonNull[]\'\n" + 
+			"----------\n");
+	}
+
+}
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/regression/DevelopmentExamples.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/regression/DevelopmentExamples.java
index 3c61d84..d6f20d3 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/regression/DevelopmentExamples.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/regression/DevelopmentExamples.java
@@ -887,6 +887,69 @@
             "MyBase.bm");
     }
 
+    // super call in base method - like 4a but with relevant signature
+    public void testX11_bindingInheritance4d() {
+       
+       runConformTest(
+            new String[] {
+		"MainX114d.java",
+			    "\n" +
+			    "public class MainX114d {\n" +
+			    "    public static void main(String[] args) {\n" +
+			    "        MyBaseX114d b = new MyBaseX114d();\n" +
+			    "        MyTeamX114d t = new MyTeamX114d();\n" +
+			    "        t.activate();\n" +
+			    "        System.out.println(b.bm(\"OK\"));\n" +
+			    "        System.out.println(\"----------------\");\n" +
+			    "        MySubSubBaseX114d ssb = new MySubSubBaseX114d();\n" +
+			    "        System.out.println(ssb.bm(\"Hoki\"));\n" +
+			    "    }\n" +
+			    "}   \n" +
+			    "    \n",
+		"MyBaseX114d.java",
+			    "\n" +
+			    "public class MyBaseX114d {\n" +
+			    "    public String bm(String in) {\n" +
+			    "        System.out.println(\"MyBase.bm(\"+in+\")\");\n" +
+			    "        return \"retBase\";\n" +
+			    "    }\n" +
+			    "}\n" +
+			    "    \n",
+		"MySubBaseX114d.java",
+			    "\n" +
+			    "public class MySubBaseX114d extends MyBaseX114d {}\n" +
+			    "    \n",
+		"MySubSubBaseX114d.java",
+			    "\n" +
+			    "public class MySubSubBaseX114d extends MySubBaseX114d {\n" +
+			    "    public String bm(String in) {\n" +
+			    "        String res = super.bm(in);\n" +
+			    "        System.out.println(\"MySubSubBase.bm(\"+in+\")\");\n" +
+			    "        return res;\n" +
+			    "    }\n" +
+			    "}\n" +
+			    "    \n",
+		"MyTeamX114d.java",
+			    "\n" +
+			    "public team class MyTeamX114d {\n" +
+			    "    public class MyRoleX114d playedBy MyBaseX114d {\n" +
+			    "        public void rm(String in) {\n" +
+			    "            System.out.println(\"MyTeam.MyRole.rm(\"+in+\")\");\n" +
+			    "        }\n" +
+			    "        rm <- after bm;\n" +
+			    "    }\n" +
+			    "}\n" +
+			    "    \n"
+            },
+            "MyBase.bm(OK)\n" +
+			"MyTeam.MyRole.rm(OK)\n" +
+			"retBase\n" +
+			"----------------\n" +
+			"MyBase.bm(Hoki)\n" +
+			"MySubSubBase.bm(Hoki)\n" +
+			"MyTeam.MyRole.rm(Hoki)\n" +
+			"retBase");
+    }
     // after callin inherited from super role, before callin to the same base method added
     // X.1.1-otjld-binding-inheritance-5
     public void testX11_bindingInheritance5() {
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/ExplicitRoleCreation.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/ExplicitRoleCreation.java
index 7893d72..b4eb9e5 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/ExplicitRoleCreation.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/ExplicitRoleCreation.java
@@ -3830,5 +3830,50 @@
             },
             "OK");
     }
+
+    // a role is bound to a lower role with a non-visible constructor invoked via base()
+    // addition: one more arg (2byte)
+    public void test2335_creatingRoleOfRegularInner2b() {
+       
+       runConformTest(
+            new String[] {
+		"Team2335crori2b_2.java",
+			    "\n" +
+			    "import b.Team2335crori2b_1;\n" +
+			    "@SuppressWarnings(\"decapsulation\")\n" +
+			    "public team class Team2335crori2b_2 {\n" +
+			    "    protected final Team2335crori2b_1 lower = new Team2335crori2b_1();\n" +
+			    "    protected class R playedBy Inner<@lower> {\n" +
+			    "        protected R(Team2335crori2b_1 outer) {\n" +
+			    "            outer.base(\"OK\", 1.2345d);\n" + // TODO: is outer. acceptable, shouldn't it always be lower.base()??
+			    "        }\n" +
+			    "        String getVal() -> get String val;\n" +
+			    "        protected void print() {\n" +
+			    "            System.out.print(getVal());\n" +
+			    "        }\n" +
+			    "    }\n" +
+			    "    void test() {\n" +
+			    "        new R(lower).print();\n" +
+			    "    }\n" +
+			    "    public static void main(String[] args) {\n" +
+			    "        new Team2335crori2b_2().test();\n" +
+			    "    }\n" +
+			    "}\n" +
+			    "    \n",
+		"b/Team2335crori2b_1.java",
+			    "\n" +
+			    "package b;\n" +
+			    "public team class Team2335crori2b_1 {\n" +
+			    "    protected class Inner {\n" +
+			    "        String val;\n" +
+			    "        protected Inner(String v, double d) {\n" +
+			    "            this.val = v+String.valueOf(d);\n" +
+			    "        }\n" +
+			    "    }\n" +
+			    "}\n" +
+			    "    \n"
+            },
+            "OK1.2345");
+    }
     // no test with private constructor: can never be called from  outside (has no creation method).
 }
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/AcquisitionAndInheritanceOfRoleClasses.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/AcquisitionAndInheritanceOfRoleClasses.java
index 7cc39c6..39e6366 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/AcquisitionAndInheritanceOfRoleClasses.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/AcquisitionAndInheritanceOfRoleClasses.java
@@ -483,6 +483,57 @@
             "OK");
     }
 
+    // a role class accesses an overwritten feature that it indirectly inherited from its implicit super role
+    // challenge tsuper from private
+    public void _test132_roleInheritedFeatureAccess2b() {
+       
+       runConformTest(
+            new String[] {
+		"T132rfa2bMain.java",
+			    "\n" +
+			    "public class T132rfa2bMain {\n" +
+			    "    public static void main(String[] args) {\n" +
+			    "        Team132rfa2b_3 t = new Team132rfa2b_3();\n" +
+			    "\n" +
+			    "        System.out.print(t.getValue());\n" +
+			    "    }\n" +
+			    "}\n" +
+			    "    \n",
+		"Team132rfa2b_1.java",
+			    "\n" +
+			    "public team class Team132rfa2b_1 {\n" +
+			    "    protected class Role132rfa2b {\n" +
+			    "        private String getValueInternal() {\n" +
+			    "            return \"K\";\n" +
+			    "        }\n" +
+			    "    }\n" +
+			    "}\n" +
+			    "    \n",
+		"Team132rfa2b_2.java",
+			    "\n" +
+			    "public team class Team132rfa2b_2 extends Team132rfa2b_1 {}\n" +
+			    "    \n",
+		"Team132rfa2b_3.java",
+			    "\n" +
+			    "public team class Team132rfa2b_3 extends Team132rfa2b_2 {\n" +
+			    "    protected class Role132rfa2b {\n" +
+			    "        private String getValueInternal() {\n" +
+			    "            return \"O\"+tsuper.getValueInternal();\n" +
+			    "        }\n" +
+			    "        protected String getValue() {\n" +
+			    "            return getValueInternal();\n" +
+			    "        }\n" +
+			    "    }\n" +
+			    "\n" +
+			    "    public String getValue() {\n" +
+			    "        return new Role132rfa2b().getValue();\n" +
+			    "    }\n" +
+			    "}\n" +
+			    "    \n"
+            },
+            "OK");
+    }
+
     // a role class accesses a feature inherited from its direct explicit super role
     // 1.3.2-otjld-role-inherited-feature-access-3
     public void test132_roleInheritedFeatureAccess3() {
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/ImplicitInheritance.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/ImplicitInheritance.java
index b633483..234bd58 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/ImplicitInheritance.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/ImplicitInheritance.java
@@ -1373,22 +1373,22 @@
     public void test0c16_implicitInheritanceRegression2() {
     	runConformTest(
     		new String[]{
-    	"p2/SubTeam.java",
-    		"package p2;\n" +
-    		"import p1.SuperTeam;\n" +
+    	"p2b/SubTeam.java",
+    		"package p2b;\n" +
+    		"import p2a.SuperTeam;\n" +
     		"public team class SubTeam extends SuperTeam {\n" +
     		"	public abstract class R {}\n" +
     		"}\n",
-    	"p1/SuperTeam.java",
-    		"package p1;\n" +
+    	"p2a/SuperTeam.java",
+    		"package p2a;\n" +
     		"public team class SuperTeam {\n" +
     		"	final OtherTeam other=new OtherTeam();\n" +
     		"	public abstract class R {\n" +
     		"		OR<@other> otherRole;\n" +
     		"	}\n" +
     		"}\n",
-    	"p1/OtherTeam.java",
-    		"package p1;\n" +
+    	"p2a/OtherTeam.java",
+    		"package p2a;\n" +
     		"public team class OtherTeam {\n" +
     		"	public abstract class OR {}\n" +
     		"}\n"
@@ -1399,10 +1399,10 @@
     public void test0c16_implicitInheritanceRegression3() {
     	runConformTest(
     		new String[]{
-    	"p2/SubTeam.java",
-    		"package p2;\n" +
+    	"p3b/SubTeam.java",
+    		"package p3b;\n" +
     		"import java.lang.annotation.*;\n" +
-    		"import p1.SuperTeam;\n" +
+    		"import p3a.SuperTeam;\n" +
     		"public team class SubTeam extends SuperTeam {\n" +
     		"	public void test() {\n" +
     		"		new R().test(ElementType.METHOD);\n" +
@@ -1411,8 +1411,8 @@
     		"		new SubTeam().test();\n" +
     		"	}\n" +
     		"}\n",
-    	"p1/SuperTeam.java",
-    		"package p1;\n" +
+    	"p3a/SuperTeam.java",
+    		"package p3a;\n" +
     		"import java.lang.annotation.*;\n" +
     		"public team class SuperTeam {\n" +
     		"	public class R {\n" +