You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2019/01/30 21:57:18 UTC

[isis] branch 2033-IoC updated: ISIS-2033: introduces a new Oid 'UniversalOid'

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch 2033-IoC
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/2033-IoC by this push:
     new 188bcf6  ISIS-2033: introduces a new Oid 'UniversalOid'
188bcf6 is described below

commit 188bcf65e2b8c6772d2ecbf73025cac7aef35966
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Jan 30 22:57:10 2019 +0100

    ISIS-2033: introduces a new Oid 'UniversalOid'
    
    to access/reference Beans and Entities managed ba external IoC
    containers or PersistenceContexts
    
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-2033
---
 .../applib/services/inject/ServiceInjector.java    |   2 +-
 .../apache/isis/commons/internal/base/_Casts.java  |  60 +++++++++
 .../isis/commons/internal/base/_Strings.java       |  25 ++++
 .../commons/internal/base/_Strings_FastSplit.java  |  48 +++++++
 .../org/apache/isis/commons/internal/cdi/_CDI.java |  43 +++++-
 .../internal/cdi/_CDI_AmbiguousInstance.java       |  58 ++++++++
 .../commons/internal/cdi/_CDI_EmptyInstance.java   |  65 +++++++++
 .../internal/cdi/_CDI_SingletonInstance.java       |  63 +++++++++
 .../org/apache/isis/commons/internal/uri/_URI.java | 146 +++++++++++++++++++++
 .../isis/core/metamodel/adapter/ObjectAdapter.java |   2 +-
 .../metamodel/adapter/ObjectAdapterProvider.java   |  15 ---
 .../isis/core/metamodel/adapter/oid/Oid.java       |   8 ++
 .../isis/core/metamodel/adapter/oid/Oid_Root.java  |  11 ++
 .../core/metamodel/adapter/oid/Oid_Universal.java  | 141 ++++++++++++++++++++
 .../core/metamodel/adapter/oid/UniversalOid.java   |   9 ++
 .../isis/core/metamodel/spec/ManagedObject.java    |  15 ++-
 .../metamodel/specloader/SpecificationLoader.java  |   3 +-
 .../isis/core/plugins/ioc/weld/WeldFactory.java    |   1 -
 .../core/runtime/contextmanger/ContextHandler.java |  28 ++++
 .../core/runtime/contextmanger/ContextManager.java |  12 ++
 .../contextmanger/ManagedObjectResolver.java       |  33 +++++
 .../contextmanger/UniversalContextManager.java     |  73 +++++++++++
 .../runtime/persistence/adapter/PojoAdapter.java   |  22 +++-
 .../adaptermanager/ObjectAdapterContext.java       |  10 +-
 ...ctAdapterContext_ObjectAdapterByIdProvider.java |  47 ++++++-
 ...ObjectAdapterContext_ObjectAdapterProvider.java |  10 +-
 .../ObjectAdapterContext_OidProviders.java         | 109 ++++++++-------
 .../adaptermanager/factories/OidFactory.java       |   5 +-
 .../factories/OidFactory_Builder.java              |  15 ++-
 .../system/session/IsisSessionProducerBean.java    |   5 +-
 .../wicket/viewer/IsisWicketApplication.java       |   2 +-
 .../wicket/ConverterForObjectAdapterMemento.java   |   2 +-
 .../model/mementos/ObjectAdapterMemento.java       |  22 +++-
 .../wicket/model/models/EntityCollectionModel.java |   2 +-
 .../viewer/wicket/model/models/EntityModel.java    |   6 +-
 .../model/models/EntityModelForReference.java      |   2 +-
 .../viewer/wicket/model/models/ValueModel.java     |   2 +-
 .../entityactions/EntityActionLinkFactory.java     |   2 +-
 .../wicket/ui/panels/FormExecutorDefault.java      |  28 +++-
 .../application/manifest/menubars.layout.xml       |  13 ++
 .../modules/spring/SpringDataJPADemoHandler.java   | 100 ++++++++++++++
 41 files changed, 1152 insertions(+), 113 deletions(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java b/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java
index 352c5d1..c700f98 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java
@@ -45,7 +45,7 @@ public interface ServiceInjector {
     @Deprecated // use ServiceRegistry instead
     <T> T lookupServiceElseFail(final Class<T> serviceClass);
     
-//FIXME [2033]
+//FIXME [2033] remove comments ...
 //    /**
 //     * This is mutable internally, but only ever exposed (in {@link #streamRegisteredServices()}).
 //     */
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Casts.java b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Casts.java
index a8365a9..ac56798 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Casts.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Casts.java
@@ -21,6 +21,7 @@ package org.apache.isis.commons.internal.base;
 
 import static org.apache.isis.commons.internal.base._With.requires;
 
+import java.util.function.BiFunction;
 import java.util.function.Supplier;
 
 import javax.annotation.Nullable;
@@ -63,4 +64,63 @@ public final class _Casts {
 
     }
 
+    /**
+     * Dependent on whether left or right can be cast to {@code cls}, the appropriate functional 
+     * interface is chosen to produce the result.
+     * @param left
+     * @param right
+     * @param cls
+     * @param onBothCast
+     * @param onLeftCast
+     * @param onRightCast
+     * @param onNonCast
+     * @return
+     */
+    public static <T, R, U, V> R castThenApply(
+    		@Nullable U left, 
+    		@Nullable V right,
+    		Class<T> cls, 
+    		BiFunction<T, T, R> onBothCast,
+    		BiFunction<T, V, R> onLeftCast,
+    		BiFunction<U, T, R> onRightCast,
+    		BiFunction<U, V, R> onNonCast) {
+
+    	requires(cls, "cls");
+    	
+    	T left_casted=null, right_casted=null;
+    	boolean left_not_casted=false, right_not_casted=false;
+    	
+    	if(left==null) {
+    		left_casted = null;
+    	} else if(cls.isAssignableFrom(left.getClass())) {
+    		left_casted = cls.cast(left);
+    	} else {
+    		left_not_casted = true;
+    	}
+    	
+    	if(right==null) {
+    		right_casted = null;
+    	} else if(cls.isAssignableFrom(right.getClass())) {
+    		right_casted = cls.cast(right);
+    	} else {
+    		right_not_casted = true;
+    	}
+    	
+    	if(left_not_casted && right_not_casted) {
+    		return onNonCast.apply(left, right);
+    	}
+
+    	if(!left_not_casted && !right_not_casted) {
+    		return onBothCast.apply(left_casted, right_casted);
+    	}
+    	
+    	if(left_not_casted) {
+    		return onRightCast.apply(left, right_casted);
+    	}
+    	
+    	return onLeftCast.apply(left_casted, right);
+    	
+    }
+    
+    
 }
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java
index 151cfc7..7e6226f 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java
@@ -33,6 +33,8 @@ import java.util.Optional;
 import java.util.Scanner;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 import java.util.function.UnaryOperator;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
@@ -365,6 +367,29 @@ public final class _Strings {
         }
         return delimiterPattern.splitAsStream(input);
     }
+    
+
+    public static void splitThenAccept(
+    		@Nullable final String input, 
+    		final String separator, 
+    		final BiConsumer<String, String> onNonEmptySplit,
+    		final Consumer<String> onNonEmptyLhs,
+    		final Consumer<String> onNonEmptyRhs) {
+    	
+    	_Strings_FastSplit.splitThenAccept(input, separator, onNonEmptySplit, onNonEmptyLhs, onNonEmptyRhs);
+    }
+    
+    public static void splitThenAcceptEmptyAsNull(
+    		@Nullable final String input, 
+    		final String separator, 
+    		final BiConsumer<String, String> onSplit) {
+    	
+    	_Strings_FastSplit.splitThenAccept(input, separator, onSplit, 
+    			lhs->onSplit.accept(lhs, null), 
+    			rhs->onSplit.accept(null, rhs));
+    }
+    
+    
 
     // -- REPLACEMENT OPERATORS
 
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings_FastSplit.java b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings_FastSplit.java
new file mode 100644
index 0000000..1eac561
--- /dev/null
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings_FastSplit.java
@@ -0,0 +1,48 @@
+package org.apache.isis.commons.internal.base;
+
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+import javax.annotation.Nullable;
+
+class _Strings_FastSplit {
+
+	public static void splitThenAccept(
+    		@Nullable final String input, 
+    		final String separator, 
+    		BiConsumer<String, String> onNonEmptySplit,
+    		Consumer<String> onNonEmptyLhs,
+    		Consumer<String> onNonEmptyRhs) {
+    	
+        if(_Strings.isEmpty(input)) {
+        	// skip
+            return;
+        }
+        
+        // we have a non-empty string
+        
+        final int p = input.indexOf(separator);
+        if(p<1){
+			if(p==-1) {
+				// separator not found
+				onNonEmptyLhs.accept(input);
+				return;
+			}
+			if(p==0) {
+				// empty lhs in string
+				if(input.length()>separator.length()) {
+					onNonEmptyRhs.accept(input);
+				}
+				return;
+			}
+		}
+        final int q = p + separator.length();
+		if(q==input.length()) {
+			// empty rhs
+			onNonEmptyLhs.accept(input.substring(0, p));
+			return;
+		}
+		onNonEmptySplit.accept(input.substring(0, p), input.substring(q));
+    }
+	
+}
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI.java b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI.java
index 79b5277..0400caf 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI.java
@@ -18,6 +18,10 @@
  */
 package org.apache.isis.commons.internal.cdi;
 
+import static org.apache.isis.commons.internal.base._NullSafe.isEmpty;
+import static org.apache.isis.commons.internal.base._NullSafe.stream;
+import static org.apache.isis.commons.internal.base._With.requires;
+
 import java.lang.annotation.Annotation;
 import java.util.Collection;
 import java.util.List;
@@ -28,6 +32,7 @@ import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import javax.annotation.Nullable;
 import javax.enterprise.inject.Any;
 import javax.enterprise.inject.Instance;
 import javax.enterprise.inject.spi.Bean;
@@ -37,14 +42,13 @@ import javax.enterprise.inject.spi.CDIProvider;
 import javax.enterprise.util.AnnotationLiteral;
 import javax.inject.Qualifier;
 
+import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.context._Context;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.commons.internal.functions._Functions.CheckedRunnable;
 import org.apache.isis.core.plugins.ioc.IocPlugin;
 
-import static org.apache.isis.commons.internal.base._NullSafe.isEmpty;
-import static org.apache.isis.commons.internal.base._NullSafe.stream;
-import static org.apache.isis.commons.internal.base._With.requires;
+import lombok.val;
 
 /**
  * <h1>- internal use only -</h1>
@@ -221,6 +225,38 @@ public final class _CDI {
         Set<Bean<?>> beans = beanManager.getBeans(Object.class, _CDI.QUALIFIER_ANY);
         return beans.stream();
 	}
+    
+    // -- FACTORIES
+    
+	public static class InstanceFactory {
+
+		public static <T> Instance<T> empty() {
+			return new _CDI_EmptyInstance<>();
+		}
+		
+		public static <T> Instance<T> singleton(@Nullable T pojo) {
+			if(pojo==null) {
+				return empty();
+			}
+			return _CDI_SingletonInstance.of(pojo);
+		}
+
+		public static <T> Instance<T> ambiguous(@Nullable Collection<T> collection) {
+			val size = _NullSafe.size(collection);
+			if(size==0) {
+				return empty();
+			} 
+			if(size==1) {
+				if(collection instanceof List) {
+					// just to reduce heap pollution when collection is a list
+					return singleton(((List<T>)collection).get(0));
+				} 
+				return singleton(collection.iterator().next());
+			}
+			return _CDI_AmbiguousInstance.of(collection);
+		}
+		
+	}
         
     // -- HELPER
     
@@ -246,7 +282,6 @@ public final class _CDI {
             return null;
         }
     }
-
 	
 
 
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_AmbiguousInstance.java b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_AmbiguousInstance.java
new file mode 100644
index 0000000..1c52594
--- /dev/null
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_AmbiguousInstance.java
@@ -0,0 +1,58 @@
+package org.apache.isis.commons.internal.cdi;
+
+import java.lang.annotation.Annotation;
+import java.util.Iterator;
+
+import javax.enterprise.inject.Instance;
+import javax.enterprise.util.TypeLiteral;
+
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor(staticName="of")
+final class _CDI_AmbiguousInstance<T> implements Instance<T> {
+
+	private final Iterable<T> iterable;
+	
+	@Override
+	public Iterator<T> iterator() {
+		return iterable.iterator();
+	}
+
+	@Override
+	public T get() {
+		throw _Exceptions.notImplemented();
+	}
+
+	@Override
+	public Instance<T> select(Annotation... qualifiers) {
+		throw _Exceptions.notImplemented();
+	}
+
+	@Override
+	public <U extends T> Instance<U> select(Class<U> subtype, Annotation... qualifiers) {
+		throw _Exceptions.notImplemented();
+	}
+
+	@Override
+	public <U extends T> Instance<U> select(TypeLiteral<U> subtype, Annotation... qualifiers) {
+		throw _Exceptions.notImplemented();
+	}
+
+	@Override
+	public boolean isUnsatisfied() {
+		return false;
+	}
+
+	@Override
+	public boolean isAmbiguous() {
+		return true;
+	}
+
+	@Override
+	public void destroy(T instance) {
+		// ignore
+	}
+
+}
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_EmptyInstance.java b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_EmptyInstance.java
new file mode 100644
index 0000000..28d5e8c
--- /dev/null
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_EmptyInstance.java
@@ -0,0 +1,65 @@
+package org.apache.isis.commons.internal.cdi;
+
+import java.lang.annotation.Annotation;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import javax.enterprise.inject.Instance;
+import javax.enterprise.util.TypeLiteral;
+
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+
+final class _CDI_EmptyInstance<T> implements Instance<T> {
+
+	@Override
+	public Iterator<T> iterator() {
+		return new Iterator<T>() {
+
+			@Override
+			public boolean hasNext() {
+				return false;
+			}
+
+			@Override
+			public T next() {
+				throw new NoSuchElementException();
+			}
+		};
+	}
+
+	@Override
+	public T get() {
+		throw new NoSuchElementException();
+	}
+
+	@Override
+	public Instance<T> select(Annotation... qualifiers) {
+		throw _Exceptions.notImplemented();
+	}
+
+	@Override
+	public <U extends T> Instance<U> select(Class<U> subtype, Annotation... qualifiers) {
+		throw _Exceptions.notImplemented();
+	}
+
+	@Override
+	public <U extends T> Instance<U> select(TypeLiteral<U> subtype, Annotation... qualifiers) {
+		throw _Exceptions.notImplemented();
+	}
+
+	@Override
+	public boolean isUnsatisfied() {
+		return true;
+	}
+
+	@Override
+	public boolean isAmbiguous() {
+		return false;
+	}
+
+	@Override
+	public void destroy(T instance) {
+		// ignore
+	}
+
+}
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_SingletonInstance.java b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_SingletonInstance.java
new file mode 100644
index 0000000..33cec4c
--- /dev/null
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_SingletonInstance.java
@@ -0,0 +1,63 @@
+package org.apache.isis.commons.internal.cdi;
+
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.Iterator;
+
+import javax.enterprise.inject.Instance;
+import javax.enterprise.util.TypeLiteral;
+
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor(staticName="of")
+final class _CDI_SingletonInstance<T> implements Instance<T> {
+
+	private final T singleton;
+	private Iterable<T> iterable;
+	
+	@Override
+	public Iterator<T> iterator() {
+		if(iterable==null) {
+			iterable = Collections.singletonList(singleton);
+		}
+		return iterable.iterator();
+	}
+
+	@Override
+	public T get() {
+		return singleton;
+	}
+
+	@Override
+	public Instance<T> select(Annotation... qualifiers) {
+		throw _Exceptions.notImplemented();
+	}
+
+	@Override
+	public <U extends T> Instance<U> select(Class<U> subtype, Annotation... qualifiers) {
+		throw _Exceptions.notImplemented();
+	}
+
+	@Override
+	public <U extends T> Instance<U> select(TypeLiteral<U> subtype, Annotation... qualifiers) {
+		throw _Exceptions.notImplemented();
+	}
+
+	@Override
+	public boolean isUnsatisfied() {
+		return false;
+	}
+
+	@Override
+	public boolean isAmbiguous() {
+		return false;
+	}
+
+	@Override
+	public void destroy(T instance) {
+		// ignore
+	}
+
+}
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/uri/_URI.java b/core/commons/src/main/java/org/apache/isis/commons/internal/uri/_URI.java
new file mode 100644
index 0000000..306f33d
--- /dev/null
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/uri/_URI.java
@@ -0,0 +1,146 @@
+package org.apache.isis.commons.internal.uri;
+
+import static org.apache.isis.commons.internal.base._Strings.splitThenAcceptEmptyAsNull;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.isis.commons.internal.base._Strings;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.uri._URI.UoidDto.UoidDtoBuilder;
+import org.apache.isis.commons.internal.uri._URI.UriDto.UriDtoBuilder;
+
+import lombok.Builder;
+import lombok.ToString;
+import lombok.val;
+
+/**
+ * @since 2.0.0-M3
+ */
+public final class _URI {
+	
+	// -- URI
+	
+	public static UriDtoBuilder uriBuilder() {
+		return UriDto.builder();
+	}
+	
+	public static UriDtoBuilder uriBuilder(URI template) {
+		val builder = UriDto.builder()
+				.scheme(template.getScheme())
+				.authority(template.getAuthority())
+				.path(template.getPath())
+				.query(template.getQuery())
+				.fragment(template.getFragment());
+		return builder;
+	}
+	
+	@Builder @ToString
+	public static class UriDto {
+		private final String scheme;
+		private final String authority;
+		private final String path;
+		private final String query;
+		private final String fragment;
+		
+		public URI toURI() {
+			try {
+				return new URI(scheme, authority, path, query, fragment);
+			} catch (URISyntaxException e) {
+				throw _Exceptions.unrecoverable(e);
+			}
+		}
+		
+	}
+	
+	// -- UOID
+	
+	private final static String UOID_SCHEME = "uoid";
+
+	public static boolean isUoid(String string) {
+		return string!=null && string.startsWith(UOID_SCHEME + "://");
+	}
+	
+	public static UoidDtoBuilder uoidBuilder() {
+		return UoidDto.builder();
+	}
+	
+	public static UoidDtoBuilder uoidBuilder(URI template) {
+		val builder = UoidDto.builder()
+				.scheme(template.getScheme())
+				.path(template.getPath())
+				.query(template.getQuery())
+				.fragment(template.getFragment());
+		
+		splitThenAcceptEmptyAsNull(template.getAuthority(), "@", 
+				(ctxType, rhs)->{ 
+					builder.contextType(ctxType!=null ? ContextType.valueOf(ctxType) : null);
+					
+					splitThenAcceptEmptyAsNull(rhs, ":", 
+							(cont, ctxId)->{ 
+								builder.containerType(cont!=null ? ContainerType.valueOf(cont) : null);
+								builder.contextId(ctxId);
+							});			
+				});
+		
+		
+		
+		return builder;
+				
+	}
+	
+	public static enum ContainerType {
+		cdi,
+		spring,
+		;
+	}
+	
+	public static enum ContextType {
+		beans, // InversionOfControlContainer
+		entities, // PersistenceContext
+		;
+	}
+	
+	@Builder @ToString
+	public static class UoidDto {
+		@Builder.Default private final String scheme = UOID_SCHEME;
+		@Builder.Default private final ContainerType containerType = ContainerType.cdi;
+		@Builder.Default private final ContextType contextType = ContextType.beans;
+		private final String contextId;
+		private final String path;
+		private final String query;
+		private final String fragment;
+		
+		public URI toURI() {
+			try {
+				return new URI(scheme, authority(), path, query, fragment);
+			} catch (URISyntaxException e) {
+				throw _Exceptions.unrecoverable(e);
+			}
+		}
+		
+		// -- HELPER
+		
+		private String authority() {
+			val sb = new StringBuilder();
+			if(contextType!=null) {
+				sb.append(contextType.name()).append("@");
+			}
+			if(containerType!=null) {
+				sb.append(containerType.name());
+			}
+			if(!_Strings.isEmpty(contextId)) {
+				sb.append(":").append(contextId);
+			}
+			return sb.toString();
+		}
+		
+		
+	}
+
+	//-- HELPER
+
+	private _URI() {}
+
+	
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapter.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapter.java
index 74cc47a..160730a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapter.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapter.java
@@ -77,7 +77,7 @@ public interface ObjectAdapter extends ManagedObject {
     Oid getOid();
 
     /**
-     * Returns either itself (if this is a root) or the parented collections, the
+     * Returns either itself (if this is a root) or for parented collections, the
      * adapter corresponding to their {@link ParentedOid#getParentOid() root oid}.
      */
     ObjectAdapter getAggregateRoot();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapterProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapterProvider.java
index 4d80ecb..b66baf2 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapterProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapterProvider.java
@@ -24,7 +24,6 @@ import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
-import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -44,7 +43,6 @@ public interface ObjectAdapterProvider {
      * @param pojo
      * @return oid for the given domain object 
      */
-    @Programmatic
     default @Nullable Oid oidFor(@Nullable Object domainObject) {
         return mapIfPresentElse(adapterFor(domainObject), ObjectAdapter::getOid, null);
     }
@@ -109,15 +107,12 @@ public interface ObjectAdapterProvider {
     
     public static interface Delegating extends ObjectAdapterProvider {
         
-        @Programmatic
         ObjectAdapterProvider getObjectAdapterProvider();
         
-        @Programmatic
         default ObjectAdapter adapterFor(Object domainObject) {
             return getObjectAdapterProvider().adapterFor(domainObject);
         }
 
-        @Programmatic
         default ObjectAdapter adapterFor(
                 final Object pojo,
                 final RootOid parentOid,
@@ -125,45 +120,35 @@ public interface ObjectAdapterProvider {
             return getObjectAdapterProvider().adapterFor(pojo, parentOid, collection);
         }
 
-        @Programmatic
         default ManagedObject disposableAdapterForViewModel(final Object viewModelPojo) {
             return getObjectAdapterProvider().disposableAdapterForViewModel(viewModelPojo);
         }
         
-        @Programmatic
         default ObjectSpecification specificationForViewModel(Object viewModelPojo) {
             return getObjectAdapterProvider().specificationForViewModel(viewModelPojo);
         }
 
-        @Programmatic
         default ObjectAdapter adapterForViewModel(final Object viewModelPojo, final String mementoString) {
             return getObjectAdapterProvider().adapterForViewModel(viewModelPojo, mementoString);
         }
         
-        @Programmatic
         default ObjectAdapter newTransientInstance(ObjectSpecification objectSpec) {
             return getObjectAdapterProvider().newTransientInstance(objectSpec);
         }
         
-        @Programmatic
         default ObjectAdapter recreateViewModelInstance(ObjectSpecification objectSpec, final String memento) {
             return getObjectAdapterProvider().recreateViewModelInstance(objectSpec, memento);
         }
         
-        @Programmatic
         default Stream<ObjectAdapter> streamServices() {
             return getObjectAdapterProvider().streamServices();
         }
         
-        @Programmatic
         default ObjectAdapter lookupService(String serviceId) {
             return getObjectAdapterProvider().lookupService(serviceId);
         }
         
     }
-
-
-    
     
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java
index 9ddeb17..c12947e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.core.metamodel.adapter.oid;
 
+import java.net.URI;
+
 import org.apache.isis.applib.annotation.Value;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.core.commons.encoding.Encodable;
@@ -110,6 +112,12 @@ public interface Oid extends Encodable {
             return Oid_Value.INSTANCE;
         }
         
+        public static UniversalOid universal(URI uri) {
+            return Oid_Universal.of(uri);
+        }
+        
+        // -- LEGACY
+        
         public static RootOid ofBookmark(final Bookmark bookmark) {
             return Oid_Root.of(ObjectSpecId.of(bookmark.getObjectType()), 
                     bookmark.getIdentifier(), Oid_State.from(bookmark), Version.empty());
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
index 98f1d67..57cfddc 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
@@ -25,6 +25,7 @@ import java.io.IOException;
 import java.util.Objects;
 
 import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.commons.encoding.DataInputExtended;
 import org.apache.isis.core.commons.encoding.DataOutputExtended;
 import org.apache.isis.core.commons.url.UrlDecoderUtil;
@@ -32,6 +33,8 @@ import org.apache.isis.core.metamodel.adapter.version.Version;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.schema.common.v1.OidDto;
 
+import lombok.val;
+
 final class Oid_Root implements RootOid {
 
     // -- fields
@@ -69,6 +72,14 @@ final class Oid_Root implements RootOid {
         this.state = state;
         this.version = version;
         this.hashCode = calculateHash();
+        
+        
+        val debug = this.toString(); 
+        if(debug.contains("/spring/")) {
+        	_Exceptions.throwUnexpectedCodeReach();
+        }
+        
+        
     }
 
     // -- Encodeable
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Universal.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Universal.java
new file mode 100644
index 0000000..4f33110
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Universal.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.core.metamodel.adapter.oid;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.commons.internal.base._Strings;
+import org.apache.isis.commons.internal.debug._Probe;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.uri._URI;
+import org.apache.isis.core.commons.encoding.DataOutputExtended;
+import org.apache.isis.core.metamodel.adapter.version.Version;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.schema.common.v1.OidDto;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import lombok.val;
+
+@RequiredArgsConstructor(staticName="of")
+final class Oid_Universal implements UniversalOid {
+
+    private final static long serialVersionUID = 1L;
+	private final static _Probe probe = _Probe.unlimited().label("Oid_Universal");
+    
+	private final URI universalId;
+	@Getter @Setter private Version version;
+	
+	@Override
+	public ObjectSpecId getObjectSpecId() {
+		
+		val path = universalId().getPath();
+		
+		val firstPathEntry = _Strings.splitThenStream(path, "/")
+		.filter(_Strings::isNotEmpty)
+		.findFirst()
+		.orElse(null);
+		
+		return ObjectSpecId.of(firstPathEntry);
+	}
+
+	@Override
+	public String getIdentifier() {
+		return universalId().getQuery();
+	}
+
+	@Override
+	public Bookmark asBookmark() {
+		
+		//TODO [2033] bad place to do this here, change API ?
+		//probe.println("NOT IMPLEMENTED: 'asBookmark()'");
+		
+		final String objectType = getObjectSpecId().asString(); 
+				//asBookmarkObjectState().getCode() + rootOid.getObjectSpecId().asString();
+        final String identifier = universalId().getQuery();
+        		//rootOid.getIdentifier();
+        
+        return new Bookmark(objectType, identifier);
+
+	}
+
+	@Override
+	public OidDto asOidDto() {
+		_Exceptions.throwNotImplemented();
+		
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public String enString() {
+		if(version==null) {
+			return enStringNoVersion();
+		}
+		return _URI.uriBuilder(universalId)
+				.fragment(version.enString())
+				.build()
+				.toURI()
+				.toString();
+	}
+
+	@Override
+	public String enStringNoVersion() {
+		return universalId.toString();
+	}
+
+	@Override
+	public boolean isTransient() {
+		return false;
+	}
+
+	@Override
+	public boolean isViewModel() {
+		return false;
+	}
+
+	@Override
+	public boolean isPersistent() {
+		return true;
+	}
+
+	@Override
+	public Oid copy() {
+		return of(universalId());
+	}
+
+	@Override
+	public void encode(DataOutputExtended outputStream) throws IOException {
+		_Exceptions.throwNotImplemented();
+		
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	public URI universalId() {
+		return universalId;
+	}
+
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/UniversalOid.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/UniversalOid.java
new file mode 100644
index 0000000..5773b37
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/UniversalOid.java
@@ -0,0 +1,9 @@
+package org.apache.isis.core.metamodel.adapter.oid;
+
+import java.net.URI;
+
+public interface UniversalOid extends RootOid {
+
+	URI universalId();
+	
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
index 1409ff9..46bc043 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
@@ -25,8 +25,13 @@ import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
 
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Value;
+
 /**
- * Represents an instance of some element of the meta-model managed by the framework.
+ * Represents an instance of some element of the meta-model managed by the framework, 
+ * that is IoC-container provided beans or persistence-stack provided entities.  
  *
  */
 public interface ManagedObject {
@@ -42,6 +47,14 @@ public interface ManagedObject {
      */
     Object getPojo();
     
+    // -- SIMPLE
+    
+    @Value @RequiredArgsConstructor(staticName="of") 
+    public final static class SimpleManagedObject implements ManagedObject {
+        @Getter private final ObjectSpecification specification;
+        @Getter private final Object pojo;
+    }
+    
     // -- TITLE
     
     public default String titleString() {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
index 2e607ed..5cf33b2 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
@@ -66,7 +66,6 @@ import org.apache.isis.core.metamodel.specloader.validator.ValidationFailures;
 import org.apache.isis.core.runtime.threadpool.ThreadPoolExecutionMode;
 import org.apache.isis.core.runtime.threadpool.ThreadPoolSupport;
 import org.apache.isis.progmodels.dflt.ProgrammingModelFacetsJava5;
-import org.apache.isis.schema.metamodel.v1.MetamodelDto;
 import org.apache.isis.schema.utils.CommonDtoUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -216,7 +215,7 @@ public class SpecificationLoader {
 
         LOG.info("init() - done");
         
-        //FIXME [2033] remove
+        //FIXME [2033] remove debug code ...
         {
         	streamServiceClasses()
         	.forEach(service->probe.println("using service %s", service));
diff --git a/core/plugins/ioc-weld/src/main/java/org/apache/isis/core/plugins/ioc/weld/WeldFactory.java b/core/plugins/ioc-weld/src/main/java/org/apache/isis/core/plugins/ioc/weld/WeldFactory.java
index 4627805..c322b75 100644
--- a/core/plugins/ioc-weld/src/main/java/org/apache/isis/core/plugins/ioc/weld/WeldFactory.java
+++ b/core/plugins/ioc-weld/src/main/java/org/apache/isis/core/plugins/ioc/weld/WeldFactory.java
@@ -62,7 +62,6 @@ public class WeldFactory {
 	                    "org.apache.isis.core.wrapper.WrapperFactoryDefault",
 	                    "org.apache.isis.viewer.wicket.viewer.IsisWicketModule",
 	                    "org.apache.isis.applib.services.jdosupport.IsisJdoSupportDN5",
-	                    "org.apache.isis.core.runtime.services.ServiceInstantiator",
 	                    
 	                    "org.apache.wicket.cdi.AutoConversation",
 	                    "org.apache.isis.viewer.restfulobjects.rendering.RendererContext"
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextHandler.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextHandler.java
new file mode 100644
index 0000000..477c988
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextHandler.java
@@ -0,0 +1,28 @@
+package org.apache.isis.core.runtime.contextmanger;
+
+import java.net.URI;
+
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+/**
+ * @since 2.0.0-M3
+ */
+public interface ContextHandler extends ManagedObjectResolver {
+
+	/**
+	 * To support chain-of-responsibility pattern.
+	 * @param objectSpec
+	 * @return whether this manager sees itself responsible to manage objects represented by given objectSpec
+	 */
+	boolean recognizes(ObjectSpecification objectSpec);
+	
+	/**
+	 * To support chain-of-responsibility pattern.
+	 * @param uri
+	 * @return whether this manager sees itself responsible to manage objects represented by given uri
+	 */
+	boolean recognizes(URI uri);
+	
+
+	
+}
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextManager.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextManager.java
new file mode 100644
index 0000000..69fe5ba
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextManager.java
@@ -0,0 +1,12 @@
+package org.apache.isis.core.runtime.contextmanger;
+
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+/**
+ * @since 2.0.0-M3
+ */
+public interface ContextManager extends ManagedObjectResolver {
+
+	ManagedObjectResolver resolverFor(ObjectSpecification spec);
+	
+}
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ManagedObjectResolver.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ManagedObjectResolver.java
new file mode 100644
index 0000000..08ce300
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ManagedObjectResolver.java
@@ -0,0 +1,33 @@
+package org.apache.isis.core.runtime.contextmanger;
+
+import java.net.URI;
+
+import javax.enterprise.inject.Instance;
+
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+
+/**
+ * @since 2.0.0-M3
+ */
+public interface ManagedObjectResolver {
+
+	/**
+	 * Returns object identifier, which holds sufficient information for the framework to 
+	 * retrieve a reference to given managedObject later.
+	 * 
+	 * @param managedObject
+	 * @return identifier 
+	 */
+	URI identifierOf(ManagedObject managedObject);
+	
+	
+	/**
+	 * Retrieve a reference to the ManagedObject as identified by the identifier. 
+	 * @param spec 
+	 * @param identifier
+	 * @return
+	 */
+	Instance<ManagedObject> resolve(ObjectSpecId spec, URI identifier);
+	
+}
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/UniversalContextManager.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/UniversalContextManager.java
new file mode 100644
index 0000000..7ef59ad
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/UniversalContextManager.java
@@ -0,0 +1,73 @@
+package org.apache.isis.core.runtime.contextmanger;
+
+import static org.apache.isis.commons.internal.base._With.requires;
+
+import java.net.URI;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+import lombok.val;
+
+@Singleton
+public class UniversalContextManager implements ContextManager {
+
+	@Inject Instance<ContextHandler> contextHandlers;
+	
+	@Override
+	public URI identifierOf(ManagedObject managedObject) {
+		
+		requires(managedObject, "managedObject");
+		
+		val resolver = resolverFor(managedObject.getSpecification());
+		if(resolver==null) {
+			val msg = String.format(
+					"Could not find a ContextHandler that recognizes managedObject of type %s.", managedObject);
+			throw _Exceptions.unrecoverable(msg); 
+		}
+		
+		val uri = resolver.identifierOf(managedObject);
+		
+		return uri;
+		
+	}
+
+	@Override
+	public Instance<ManagedObject> resolve(ObjectSpecId spec, URI identifier) {
+		
+		requires(identifier, "identifier");
+		
+		val instance = contextHandlers.stream()
+		.filter(handler->handler.recognizes(identifier))
+		.findFirst()
+		.map(handler->handler.resolve(spec, identifier))
+		.orElseThrow(()->{
+			val msg = String.format(
+					"Could not find a ContextHandler that recognizes identifier URI %s.", identifier);
+			return _Exceptions.unrecoverable(msg);
+		}); 
+		
+		return instance;
+	}
+
+	@Override
+	public ManagedObjectResolver resolverFor(ObjectSpecification objSpec) {
+		
+		requires(objSpec, "objSpec");
+		
+		return contextHandlers.stream()
+		.filter(handler->handler.recognizes(objSpec))
+		.findFirst()
+		.orElse(null);
+	}
+
+
+	
+	
+}
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java
index d74b22a..104b406 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java
@@ -21,10 +21,8 @@ package org.apache.isis.core.runtime.persistence.adapter;
 
 import static org.apache.isis.commons.internal.base._With.requires;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.apache.isis.commons.internal.base._Lazy;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.commons.util.ToString;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -32,12 +30,15 @@ import org.apache.isis.core.metamodel.adapter.concurrency.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.ParentedOid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.adapter.oid.UniversalOid;
 import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
 import org.apache.isis.core.metamodel.adapter.version.Version;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.security.authentication.AuthenticationSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public final class PojoAdapter implements ObjectAdapter {
 
@@ -113,6 +114,11 @@ public final class PojoAdapter implements ObjectAdapter {
     
     @Override
     public boolean isTransient() {
+    	
+    	if(oid instanceof UniversalOid) {
+    		return oid.isTransient(); //FIXME [2033] this is a quick-hack
+    	}
+    	
         if(getSpecification().isService() || getSpecification().isViewModel()) {
             // services and view models are treated as persistent objects
             return false;
@@ -122,6 +128,11 @@ public final class PojoAdapter implements ObjectAdapter {
 
     @Override
     public boolean representsPersistent() {
+    	
+    	if(oid instanceof UniversalOid) {
+    		return oid.isPersistent(); //FIXME [2033] this is a quick-hack
+    	}
+    	
         if(getSpecification().isService() || getSpecification().isViewModel()) {
             // services and view models are treated as persistent objects
             return true;
@@ -131,6 +142,11 @@ public final class PojoAdapter implements ObjectAdapter {
 
     @Override
     public boolean isDestroyed() {
+    	
+    	if(oid instanceof UniversalOid) {
+    		return false; //FIXME [2033] this is a quick-hack
+    	}
+    	
         if(getSpecification().isService() || getSpecification().isViewModel()) {
             // services and view models are treated as persistent objects
             return false;
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext.java
index 6d78ee1..134931c 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext.java
@@ -40,7 +40,9 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.core.runtime.contextmanger.ContextManager;
 import org.apache.isis.core.runtime.memento.Data;
+import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.security.authentication.AuthenticationSession;
 
@@ -76,6 +78,7 @@ final public class ObjectAdapterContext {
     final ObjectAdapterContext_ObjectCreation objectCreationMixin;
     private final ObjectAdapterContext_LifecycleEventSupport lifecycleEventMixin;
     private final ServiceInjector servicesInjector;
+    final ContextManager contextManager;
 
     private ObjectAdapterContext(
             ServiceInjector servicesInjector, 
@@ -89,7 +92,10 @@ final public class ObjectAdapterContext {
         this.mementoSupportMixin = new ObjectAdapterContext_MementoSupport(this, persistenceSession);
         this.serviceLookupMixin = new ObjectAdapterContext_ServiceLookup(this, servicesInjector);
         this.newIdentifierMixin = new ObjectAdapterContext_NewIdentifier(this, metaModelContext, persistenceSession);
-        this.objectAdapterByIdProviderMixin = new ObjectAdapterContext_ObjectAdapterByIdProvider(this, metaModelContext, persistenceSession, authenticationSession);
+        
+        this.contextManager = IsisContext.getServiceRegistry().lookupServiceElseFail(ContextManager.class);
+        
+        this.objectAdapterByIdProviderMixin = new ObjectAdapterContext_ObjectAdapterByIdProvider(this, contextManager, metaModelContext, persistenceSession, authenticationSession);
         this.dependencyInjectionMixin = new ObjectAdapterContext_DependencyInjection(this, persistenceSession);
         this.objectCreationMixin = new ObjectAdapterContext_ObjectCreation(this, metaModelContext, persistenceSession);
         this.lifecycleEventMixin = new ObjectAdapterContext_LifecycleEventSupport(this, metaModelContext, persistenceSession);
@@ -102,6 +108,8 @@ final public class ObjectAdapterContext {
                 authenticationSession, 
                 specificationLoader, 
                 persistenceSession);
+        
+        
     }
 
     // -- DEBUG
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterByIdProvider.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterByIdProvider.java
index 5add0ce..9606686 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterByIdProvider.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterByIdProvider.java
@@ -20,13 +20,12 @@ package org.apache.isis.core.runtime.system.persistence.adaptermanager;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Stream;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.commons.ensure.Ensure;
 import org.apache.isis.core.metamodel.MetaModelContext;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -34,15 +33,21 @@ import org.apache.isis.core.metamodel.adapter.ObjectAdapterByIdProvider;
 import org.apache.isis.core.metamodel.adapter.concurrency.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.adapter.oid.UniversalOid;
 import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
 import org.apache.isis.core.metamodel.adapter.version.Version;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.core.runtime.contextmanger.ContextManager;
 import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
 import org.apache.isis.core.runtime.persistence.PojoRecreationException;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.security.authentication.AuthenticationSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import lombok.val;
 
 /**
  * package private mixin for ObjectAdapterContext
@@ -59,18 +64,23 @@ class ObjectAdapterContext_ObjectAdapterByIdProvider implements ObjectAdapterByI
     private final PersistenceSession persistenceSession;
     private final SpecificationLoader specificationLoader;
     private final AuthenticationSession authenticationSession;
+    private final ContextManager contextManager;
     private final boolean concurrencyCheckingGloballyEnabled;
     
     ObjectAdapterContext_ObjectAdapterByIdProvider(
             ObjectAdapterContext objectAdapterContext,
+            ContextManager contextManager,
             MetaModelContext metaModelContext,
             PersistenceSession persistenceSession,
             AuthenticationSession authenticationSession) {
         
+    	Objects.requireNonNull(contextManager);
+    	
         this.objectAdapterContext = objectAdapterContext;
         this.persistenceSession = persistenceSession;
         this.specificationLoader = metaModelContext.getSpecificationLoader();
         this.authenticationSession = authenticationSession;
+        this.contextManager = contextManager;
         
         this.concurrencyCheckingGloballyEnabled = 
                 !ConcurrencyChecking.isGloballyDisabled(persistenceSession.getConfiguration());
@@ -108,7 +118,7 @@ class ObjectAdapterContext_ObjectAdapterByIdProvider implements ObjectAdapterByI
             final RootOid rootOid,
             final ConcurrencyChecking concurrencyChecking) {
                 
-        /* FIXME[ISIS-1976] SPI for adapterFor(RootOid)
+        /* FIXME [ISIS-1976] SPI for adapterFor(RootOid)
          * https://github.com/apache/isis/pull/121#discussion_r215889748
          * 
          * Eventually I'm hoping that this code will simplify and then become pluggable.
@@ -125,8 +135,33 @@ class ObjectAdapterContext_ObjectAdapterByIdProvider implements ObjectAdapterByI
          * into some other datastore. So really my "PersistenceProvider" is a
          * generalization of that concept).
          */
-        
-        //FIXME[ISIS-1976] remove guard
+    	
+    	if(rootOid instanceof UniversalOid) {
+    		
+    		Objects.requireNonNull(rootOid);
+    		
+    		val universalOid = (UniversalOid) rootOid;
+    		val spec = universalOid.getObjectSpecId();
+    		val instance = contextManager.resolve(spec, universalOid.universalId());
+    		
+    		if(instance.isResolvable()) {
+    			val managedObject = instance.get();
+    			return objectAdapterContext.getFactories().createRootAdapter(managedObject.getPojo(), rootOid);	
+    		} else if(instance.isAmbiguous()) {
+    			
+    			//FIXME [2033] handle ambiguity
+    			throw _Exceptions.notImplemented();
+    			
+    		} else {
+    			
+    			//FIXME [2033] handle no such element
+    			throw _Exceptions.notImplemented();
+    		}
+    		
+    		
+    	}
+    	
+        //FIXME [ISIS-1976] remove guard
         final ObjectAdapter serviceAdapter = objectAdapterContext.lookupServiceAdapterFor(rootOid);
         if (serviceAdapter != null) {
             //throw _Exceptions.unexpectedCodeReach();
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterProvider.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterProvider.java
index 90ea7d7..b829ddb 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterProvider.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterProvider.java
@@ -35,6 +35,7 @@ import org.apache.isis.core.metamodel.MetaModelContext;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapterProvider;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.adapter.oid.UniversalOid;
 import org.apache.isis.core.metamodel.services.ServiceUtil;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -72,8 +73,8 @@ class ObjectAdapterContext_ObjectAdapterProvider implements ObjectAdapterProvide
         
         this.oidFactory = OidFactory.builder(pojo->specificationLoader.loadSpecification(pojo.getClass()))
                 .add(new ObjectAdapterContext_OidProviders.GuardAgainstRootOid())
+                .add(new ObjectAdapterContext_OidProviders.OidForManagedContexts())
                 .add(new ObjectAdapterContext_OidProviders.OidForServices())
-                .add(new ObjectAdapterContext_OidProviders.OidForManagedBeans())
                 .add(new ObjectAdapterContext_OidProviders.OidForValues())
                 .add(new ObjectAdapterContext_OidProviders.OidForViewModels())
                 .add(new ObjectAdapterContext_OidProviders.OidForPersistent())
@@ -88,10 +89,13 @@ class ObjectAdapterContext_ObjectAdapterProvider implements ObjectAdapterProvide
             return null;
         }
         
-        //FIXME [2033] the pojo might be a managed object (eg. by Spring or CDI), this is new 
-        
         final RootOid rootOid = oidFactory.oidFor(pojo);
         final ObjectAdapter newAdapter = objectAdapterContext.getFactories().createRootAdapter(pojo, rootOid);
+        
+        // the pojo might be a managed object (eg. by Spring or CDI), this is new
+        if(rootOid instanceof UniversalOid) {
+        	return newAdapter; // skip service injection
+        }
         return objectAdapterContext.injectServices(newAdapter);
     }
     
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_OidProviders.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_OidProviders.java
index 4421f59..699b4d6 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_OidProviders.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_OidProviders.java
@@ -18,19 +18,19 @@
  */
 package org.apache.isis.core.runtime.system.persistence.adaptermanager;
 
-import java.lang.reflect.InvocationTargetException;
+import java.util.Objects;
 import java.util.UUID;
 
-import javax.persistence.Entity;
-
-import org.apache.isis.commons.internal._Constants;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.base._Lazy;
+import org.apache.isis.commons.internal.base._Tuples;
 import org.apache.isis.core.metamodel.IsisJdoMetamodelPlugin;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.runtime.contextmanger.ContextManager;
+import org.apache.isis.core.runtime.contextmanger.ManagedObjectResolver;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.runtime.system.persistence.adaptermanager.factories.OidFactory.OidProvider;
@@ -43,31 +43,30 @@ class ObjectAdapterContext_OidProviders {
     static class GuardAgainstRootOid implements OidProvider {
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
-            return pojo instanceof RootOid;
+        public boolean isHandling(ManagedObject managedObject) {
+            return managedObject.getPojo() instanceof RootOid;
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
             throw new IllegalArgumentException("Cannot create a RootOid for pojo, "
                     + "when pojo is instance of RootOid. You might want to ask "
                     + "ObjectAdapterByIdProvider for an ObjectAdapter instead.");
         }
-
     }
     
     
     static class OidForServices implements OidProvider {
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
-            return spec.isService();
+        public boolean isHandling(ManagedObject managedObject) {
+            return managedObject.getSpecification().isService();
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
             final String identifier = PersistenceSession.SERVICE_IDENTIFIER;
-            return Oid.Factory.persistentOf(spec.getSpecId(), identifier);
+            return Oid.Factory.persistentOf(managedObject.getSpecification().getSpecId(), identifier);
         }
 
     }
@@ -77,14 +76,18 @@ class ObjectAdapterContext_OidProviders {
         private final IsisJdoMetamodelPlugin isisJdoMetamodelPlugin = IsisJdoMetamodelPlugin.get();
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+        public boolean isHandling(ManagedObject managedObject) {
             // equivalent to 'isInstanceOfPersistable = pojo instanceof Persistable'
-            final boolean isInstanceOfPersistable = isisJdoMetamodelPlugin.isPersistenceEnhanced(pojo.getClass());
+            final boolean isInstanceOfPersistable = isisJdoMetamodelPlugin
+            		.isPersistenceEnhanced(managedObject.getPojo().getClass());
             return isInstanceOfPersistable;
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
+        	val pojo = managedObject.getPojo();
+        	val spec = managedObject.getSpecification();
+        	
             final PersistenceSession persistenceSession = IsisContext.getPersistenceSession().get();
             final boolean isRecognized = persistenceSession.isRecognized(pojo);
             if(isRecognized) {
@@ -98,38 +101,40 @@ class ObjectAdapterContext_OidProviders {
         
     }
 
-    static class OidForManagedBeans implements OidProvider {
+    static class OidForManagedContexts implements OidProvider {
 
-        //FIXME [2033] this is just a PoC for 'Customer'
+    	final _Lazy<ContextManager> contextManager = _Lazy.of(()->
+    		IsisContext.getServiceRegistry().lookupServiceElseFail(ContextManager.class));
+    	
+    	private _Tuples.Tuple2<Object, ManagedObjectResolver> latestLookup; // acts as a cache
     	
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
-        	return pojo.getClass().isAnnotationPresent(Entity.class);
+        public boolean isHandling(ManagedObject managedObject) {
+        	val pojo = managedObject.getPojo();
+        	val spec = managedObject.getSpecification();
+        	
+        	val managedObjectResolver = contextManager.get().resolverFor(spec);
+        	
+        	if(managedObjectResolver!=null) {
+        		// likely to be reused below, just an optimization
+        		latestLookup = _Tuples.pair(pojo, managedObjectResolver);
+        		return true;
+        	}
+        	return false;
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
-        	try {
-				return oidForCustomer(pojo, spec);
-			} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
-					| InvocationTargetException e) {
-				throw _Exceptions.unrecoverable(e);
-			}
-        }
-        
-        private RootOid oidForCustomer(Object pojo, ObjectSpecification spec) 
-        		throws NoSuchMethodException, SecurityException, IllegalAccessException, 
-        		IllegalArgumentException, InvocationTargetException {
-        	
-        	val idGetter = pojo.getClass().getMethod("getId", _Constants.emptyClasses);
-        	Long id = (Long)idGetter.invoke(pojo, _Constants.emptyObjects);
-        	if(id!=null && id>0) {
-        		final String identifier = "" + id;
-        		return Oid.Factory.persistentOf(spec.getSpecId(), identifier);	
-        	} else {
-                final String identifier = UUID.randomUUID().toString();
-                return Oid.Factory.transientOf(spec.getSpecId(), identifier);    
-            }
+        public RootOid oidFor(ManagedObject managedObject) {
+        	val pojo = managedObject.getPojo();
+        	val spec = managedObject.getSpecification();
+
+        	val managedObjectResolver =	(latestLookup!=null && 
+        			Objects.equals(pojo, latestLookup.get_1()))
+        			? latestLookup.get_2() // use cache
+        					: contextManager.get().resolverFor(spec);
+        			
+    		val objectIdUri = managedObjectResolver.identifierOf(managedObject);
+    		return Oid.Factory.universal(objectIdUri);
         }
         
     }
@@ -137,12 +142,13 @@ class ObjectAdapterContext_OidProviders {
     static class OidForValues implements OidProvider {
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+        public boolean isHandling(ManagedObject managedObject) {
+        	val spec = managedObject.getSpecification();
             return spec.containsFacet(ValueFacet.class);
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
             return Oid.Factory.value();
         }
 
@@ -151,12 +157,16 @@ class ObjectAdapterContext_OidProviders {
     static class OidForViewModels implements OidProvider {
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+        public boolean isHandling(ManagedObject managedObject) {
+        	val spec = managedObject.getSpecification();
             return spec.containsFacet(ViewModelFacet.class);
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
+        	val pojo = managedObject.getPojo();
+        	val spec = managedObject.getSpecification();
+        	
             final ViewModelFacet recreatableObjectFacet = spec.getFacet(ViewModelFacet.class);
             final String identifier = recreatableObjectFacet.memento(pojo);
             return Oid.Factory.viewmodelOf(spec.getSpecId(), identifier);
@@ -167,12 +177,13 @@ class ObjectAdapterContext_OidProviders {
     static class OidForOthers implements OidProvider {
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+        public boolean isHandling(ManagedObject managedObject) {
             return true; // try to handle anything
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
+        	val spec = managedObject.getSpecification();
             final String identifier = UUID.randomUUID().toString();
             return Oid.Factory.transientOf(spec.getSpecId(), identifier);
         }
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory.java
index d3646ae..3b34eb7 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory.java
@@ -22,6 +22,7 @@ package org.apache.isis.core.runtime.system.persistence.adaptermanager.factories
 import java.util.function.Function;
 
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 /**
@@ -32,8 +33,8 @@ public interface OidFactory {
     RootOid oidFor(Object pojo);
     
     public interface OidProvider {
-        boolean isHandling(Object pojo, ObjectSpecification spec);
-        RootOid oidFor(Object pojo, ObjectSpecification spec);
+        boolean isHandling(ManagedObject managedObject);
+        RootOid oidFor(ManagedObject managedObject);
     }
     
     public interface OidFactoryBuilder {
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory_Builder.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory_Builder.java
index 4f4e46a..fab1201 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory_Builder.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory_Builder.java
@@ -19,16 +19,20 @@
 
 package org.apache.isis.core.runtime.system.persistence.adaptermanager.factories;
 
+import static java.util.Objects.requireNonNull;
+
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 import java.util.function.Function;
 
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.spec.ManagedObject.SimpleManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.runtime.system.persistence.adaptermanager.factories.OidFactory.OidFactoryBuilder;
 import org.apache.isis.core.runtime.system.persistence.adaptermanager.factories.OidFactory.OidProvider;
 
+import lombok.val;
+
 class OidFactory_Builder implements OidFactoryBuilder {
     
     private final List<OidProvider> handler = new ArrayList<>();
@@ -49,14 +53,15 @@ class OidFactory_Builder implements OidFactoryBuilder {
         return pojo -> {
 
             final ObjectSpecification spec = specProvider.apply(pojo);
-
+            val managedObject = SimpleManagedObject.of(spec, pojo);
+            
             final RootOid rootOid = handler.stream()
-            .filter(h->h.isHandling(pojo, spec))
+            .filter(h->h.isHandling(managedObject))
             .findFirst()
-            .map(h->h.oidFor(pojo, spec))
+            .map(h->h.oidFor(managedObject))
             .orElse(null);
 
-            Objects.requireNonNull(rootOid, () -> "Could not create an Oid for pojo: "+pojo);
+            requireNonNull(rootOid, () -> "Could not create an Oid for pojo: "+pojo);
 
             return rootOid;
         };
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionProducerBean.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionProducerBean.java
index 5cba4d2..e5c6171 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionProducerBean.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionProducerBean.java
@@ -29,14 +29,15 @@ import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSessionFactory;
 
 /**
- * @deprecated TODO [2033] 
+ * @deprecated TODO [2033] convert ...
  * Currently `IsisSessionFactory` and those singletons that depend on it 
  * (`SpecificationLoader` and `PersistenceSessionFactory`) are not life-cycle 
  * managed by CDI, instead we provide Producer Methods for these.
  * 
  * Consequently the framework is responsible for their life-cycles. 
  * 
- * We want to have CDI also manage these, which can be achieved by finally removing the `IsisSessionProducerBean` singleton.
+ * We want to have CDI also manage these, which can be achieved by finally 
+ * removing the `IsisSessionProducerBean` singleton.
  *
  */
 @Singleton
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
index 0b4ba2b..f38350a 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
@@ -253,7 +253,7 @@ implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketVi
             new CdiConfiguration(beanManager).configure(this);
 
 
-//            // FIXME [2033]
+//            // FIXME [2033] remove comments ...
 //            // create IsisSessionFactory
 //            //
 //            final Injector injector = Guice.createInjector(
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/ConverterForObjectAdapterMemento.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/ConverterForObjectAdapterMemento.java
index 6b62d8d..f944f15 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/ConverterForObjectAdapterMemento.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/ConverterForObjectAdapterMemento.java
@@ -56,7 +56,7 @@ public class ConverterForObjectAdapterMemento implements IConverter<ObjectAdapte
         final RootOid oid = RootOid.deStringEncoded(value);
         
         final ObjectAdapter adapter = getPersistenceSession().adapterFor(oid);
-        return ObjectAdapterMemento.createOrNull(adapter);
+        return ObjectAdapterMemento.mementoOf(adapter);
     }
 
     /**
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
index 66c315b..1ed2992 100644
--- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
@@ -20,14 +20,18 @@
 package org.apache.isis.viewer.wicket.model.mementos;
 
 import java.io.Serializable;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.function.Function;
 
+import javax.annotation.Nullable;
+
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.hint.HintStore;
 import org.apache.isis.commons.internal.collections._Lists;
+import org.apache.isis.commons.internal.uri._URI;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapterProvider;
 import org.apache.isis.core.metamodel.adapter.concurrency.ConcurrencyChecking;
@@ -44,6 +48,8 @@ import org.apache.isis.core.runtime.memento.Memento;
 import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 
+import lombok.val;
+
 public class ObjectAdapterMemento implements Serializable {
 
     private static final long serialVersionUID = 1L;
@@ -51,7 +57,7 @@ public class ObjectAdapterMemento implements Serializable {
     /**
      * Factory method
      */
-    public static ObjectAdapterMemento createOrNull(final ObjectAdapter adapter) {
+    public static ObjectAdapterMemento mementoOf(@Nullable final ObjectAdapter adapter) {
         if (adapter == null) {
             return null;
         }
@@ -226,6 +232,14 @@ public class ObjectAdapterMemento implements Serializable {
                     final ObjectAdapterMemento oam,
                     ConcurrencyChecking concurrencyChecking,
                     final PersistenceSession persistenceSession, final SpecificationLoader specificationLoader) {
+            	
+            	if(_URI.isUoid(oam.persistentOidStr)) {
+            		val uri = URI.create(oam.persistentOidStr);
+            		val oid = Oid.Factory.universal(uri);
+            		val objAdapter = persistenceSession.adapterFor(oid, concurrencyChecking);
+            		return objAdapter;
+            	}
+            	
                 RootOid oid = Oid.unmarshaller().unmarshal(oam.persistentOidStr, RootOid.class);
                 try {
                     final ObjectAdapter adapter = persistenceSession.adapterFor(oid, concurrencyChecking);
@@ -573,11 +587,11 @@ public class ObjectAdapterMemento implements Serializable {
         }
 
         public static Function<Object, ObjectAdapterMemento> fromPojo(final ObjectAdapterProvider adapterProvider) {
-            return pojo->ObjectAdapterMemento.createOrNull( adapterProvider.adapterFor(pojo) );
+            return pojo->ObjectAdapterMemento.mementoOf( adapterProvider.adapterFor(pojo) );
                 }
 
         public static Function<ObjectAdapter, ObjectAdapterMemento> fromAdapter() {
-            return ObjectAdapterMemento::createOrNull;
+            return ObjectAdapterMemento::mementoOf;
         }
 
         public static Function<ObjectAdapterMemento, ObjectAdapter> fromMemento(
@@ -596,7 +610,7 @@ public class ObjectAdapterMemento implements Serializable {
         }
 
         public static Function<ObjectAdapter, ObjectAdapterMemento> toMemento() {
-            return ObjectAdapterMemento::createOrNull;
+            return ObjectAdapterMemento::mementoOf;
         }
 
 
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
index f913940..8c7ddb9 100644
--- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
@@ -488,7 +488,7 @@ UiHintContainer {
 
 
     public void toggleSelectionOn(ObjectAdapter selectedAdapter) {
-        ObjectAdapterMemento selectedAsMemento = ObjectAdapterMemento.createOrNull(selectedAdapter);
+        ObjectAdapterMemento selectedAsMemento = ObjectAdapterMemento.mementoOf(selectedAdapter);
 
         // try to remove; if couldn't, then mustn't have been in there, in which case add.
         boolean removed = toggledMementosList.remove(selectedAsMemento);
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
index 4235404..8e27759 100644
--- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
@@ -177,7 +177,7 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> implements Obj
     }
 
     public EntityModel(final ObjectAdapter adapter) {
-        this(ObjectAdapterMemento.createOrNull(adapter));
+        this(ObjectAdapterMemento.mementoOf(adapter));
         setObject(adapter);
     }
 
@@ -356,7 +356,7 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> implements Obj
     @Override
     public void setObject(final ObjectAdapter adapter) {
         super.setObject(adapter);
-        adapterMemento = ObjectAdapterMemento.createOrNull(adapter);
+        adapterMemento = ObjectAdapterMemento.mementoOf(adapter);
     }
 
     public void setObjectMemento(
@@ -532,7 +532,7 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> implements Obj
                 return pending;
             }
             final ObjectAdapter adapter = entityModel.getObject();
-            return ObjectAdapterMemento.createOrNull(adapter);
+            return ObjectAdapterMemento.mementoOf(adapter);
         }
 
         @Override
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModelForReference.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModelForReference.java
index 6110b73..f4610ab 100644
--- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModelForReference.java
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModelForReference.java
@@ -91,7 +91,7 @@ public class EntityModelForReference implements ObjectAdapterModel {
     @Override
     public PageParameters getPageParameters() {
         PageParameters pageParameters = createPageParameters(getObject());
-        ObjectAdapterMemento oam = ObjectAdapterMemento.createOrNull(getObject());
+        ObjectAdapterMemento oam = ObjectAdapterMemento.mementoOf(getObject());
         HintPageParameterSerializer.hintStoreToPageParameters(pageParameters, oam);
         return pageParameters;
     }
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ValueModel.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ValueModel.java
index 2f4698e..ca05d5e 100644
--- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ValueModel.java
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ValueModel.java
@@ -34,7 +34,7 @@ public class ValueModel extends ModelAbstract<ObjectAdapter> {
     private final ObjectAdapterMemento adapterMemento;
 
     public ValueModel(final ObjectAdapter adapter) {
-        adapterMemento = ObjectAdapterMemento.createOrNull(adapter);
+        adapterMemento = ObjectAdapterMemento.mementoOf(adapter);
     }
 
     @Override
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
index 2a33d13..cdd7423 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
@@ -48,7 +48,7 @@ public final class EntityActionLinkFactory extends ActionLinkFactoryAbstract {
 
         final ObjectAdapter objectAdapter = this.targetEntityModel.load(ConcurrencyChecking.NO_CHECK);
 
-        final Boolean persistent = objectAdapter.representsPersistent();
+        final boolean persistent = objectAdapter.representsPersistent();
         if (!persistent) {
             throw new IllegalArgumentException(String.format(
                     "Object '%s' is not persistent.", objectAdapter.titleString(null)));
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
index 49d3eef..59ee34b 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
@@ -19,6 +19,7 @@ package org.apache.isis.viewer.wicket.ui.panels;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Callable;
+import java.util.function.BiFunction;
 import java.util.stream.Stream;
 
 import org.apache.isis.applib.RecoverableException;
@@ -30,9 +31,12 @@ import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerComposite;
 import org.apache.isis.applib.services.hint.HintStore;
 import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
+import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.concurrency.ConcurrencyChecking;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.adapter.oid.UniversalOid;
 import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
 import org.apache.isis.core.metamodel.facets.actions.redirect.RedirectFacet;
 import org.apache.isis.core.metamodel.facets.properties.renderunchanged.UnchangingFacet;
@@ -68,6 +72,8 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Throwables;
 
+import lombok.val;
+
 public final class FormExecutorDefault<M extends BookmarkableModel<ObjectAdapter> & ParentEntityModelProvider>
 implements FormExecutor {
 
@@ -279,10 +285,24 @@ implements FormExecutor {
             final ObjectAdapter targetAdapter,
             final ObjectAdapter resultAdapter) {
 
-        final ObjectAdapterMemento targetOam = ObjectAdapterMemento.createOrNull(targetAdapter);
-        final ObjectAdapterMemento resultOam = ObjectAdapterMemento.createOrNull(resultAdapter);
-
-        return differs(targetOam, resultOam);
+    	val left = targetAdapter.getOid();
+    	val right = resultAdapter.getOid();
+    	
+    	val differs = _Casts.castThenApply(left, right, UniversalOid.class,
+    			(l, r)-> !Objects.equals(l, r), // onBothCast
+    			(l, r) -> true, // onLeftCast
+    			(l, r) -> true, // onRightCast
+    			(l, r) -> { // onNonCast
+    				
+    				// legacy behavior, for non UniversalOid
+    				
+    		        final ObjectAdapterMemento targetOam = ObjectAdapterMemento.mementoOf(targetAdapter);
+    		        final ObjectAdapterMemento resultOam = ObjectAdapterMemento.mementoOf(resultAdapter);
+    		
+    		        return differs(targetOam, resultOam);			
+    			});
+		
+		return differs;
     }
 
     private static boolean differs(
diff --git a/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/menubars.layout.xml b/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/menubars.layout.xml
index d286f2d..9846d45 100644
--- a/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/menubars.layout.xml
+++ b/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/menubars.layout.xml
@@ -33,6 +33,19 @@
                 </mb3:serviceAction>
             </mb3:section>
         </mb3:menu>
+        
+        </mb3:menu>
+			<mb3:named>Spring</mb3:named>
+            <mb3:section>
+                <mb3:serviceAction objectType="simple.CustomerMenu" id="createCustomer">
+                    <cpt:named>Create Customer</cpt:named>
+                </mb3:serviceAction>
+                <mb3:serviceAction objectType="simple.CustomerMenu" id="findByLastName">
+                    <cpt:named>Find By Last Name</cpt:named>
+                </mb3:serviceAction>
+            </mb3:section>
+        </mb3:menu>
+        
         <mb3:menu unreferencedActions="true">
             <mb3:named>Other</mb3:named>
         </mb3:menu>
diff --git a/example/application/simpleapp/module-spring/src/main/java/domainapp/modules/spring/SpringDataJPADemoHandler.java b/example/application/simpleapp/module-spring/src/main/java/domainapp/modules/spring/SpringDataJPADemoHandler.java
new file mode 100644
index 0000000..f2a0cdd
--- /dev/null
+++ b/example/application/simpleapp/module-spring/src/main/java/domainapp/modules/spring/SpringDataJPADemoHandler.java
@@ -0,0 +1,100 @@
+package domainapp.modules.spring;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.util.UUID;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.persistence.Entity;
+import javax.persistence.EntityManager;
+
+import org.apache.isis.commons.internal._Constants;
+import org.apache.isis.commons.internal.cdi._CDI;
+import org.apache.isis.commons.internal.debug._Probe;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.uri._URI;
+import org.apache.isis.commons.internal.uri._URI.ContainerType;
+import org.apache.isis.commons.internal.uri._URI.ContextType;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObject.SimpleManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.core.runtime.contextmanger.ContextHandler;
+import org.springframework.context.ApplicationContext;
+
+import domainapp.modules.spring.dom.customer.Customer;
+import lombok.val;
+
+@Singleton
+public class SpringDataJPADemoHandler implements ContextHandler {
+	
+	private final static _Probe probe = _Probe.unlimited().label("SpringDataJPADemoHandler");
+	
+	@Inject ApplicationContext springContext;
+	@Inject SpecificationLoader specLoader;
+
+	@Override
+	public URI identifierOf(ManagedObject managedObject) {
+    	try {
+			return identifierForCustomer(managedObject.getPojo(), managedObject.getSpecification());
+		} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+				| InvocationTargetException e) {
+			throw _Exceptions.unrecoverable(e);
+		}
+	}
+
+	@Override
+	public Instance<ManagedObject> resolve(ObjectSpecId specId, URI identifier) {
+		
+		// FIXME [2033] this is just a PoC
+		
+		long id = Long.parseLong(identifier.getQuery());
+		
+		val em = springContext.getBean(EntityManager.class);
+		
+		val customer = em.find(Customer.class, id);
+		val spec = specLoader.lookupBySpecId(specId);
+		
+		val managedObject = SimpleManagedObject.of(spec, customer);
+		
+		return _CDI.InstanceFactory.singleton(managedObject);
+	}
+
+	@Override
+	public boolean recognizes(URI uri) {
+		return uri.toString().startsWith("uoid://entities@spring");
+	}
+
+	@Override
+	public boolean recognizes(ObjectSpecification objSpec) {
+		// FIXME [2033] this is just a PoC
+		return objSpec.getCorrespondingClass().isAnnotationPresent(Entity.class);
+	}
+	
+	// -- HELPER
+	
+	private URI identifierForCustomer(Object pojo, ObjectSpecification spec) 
+    		throws NoSuchMethodException, SecurityException, IllegalAccessException, 
+    		IllegalArgumentException, InvocationTargetException {
+    	
+    	val idGetter = pojo.getClass().getMethod("getId", _Constants.emptyClasses);
+    	final Long id = (Long)idGetter.invoke(pojo, _Constants.emptyObjects);
+    	final String identifier = (id!=null && id>0) 
+    			? "" + id
+    					: UUID.randomUUID().toString();
+    		
+		return _URI.uoidBuilder()
+				.containerType(ContainerType.spring)
+				.contextType(ContextType.entities)
+				.contextId(null)
+				.path("/"+spec.getSpecId().asString()+"/")
+				.query(identifier)
+				.build()
+				.toURI();
+    }
+	
+
+}