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

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

commit 66b4e3ef4b62f6da6f0ef176e046c6105bd49395
Author: Andi Huber <ahu...@apache.org>
AuthorDate: Fri Apr 13 22:47:43 2018 +0200

    ISIS-1742 fixes naive memento re-implementation in Internal API
    
    Extends BookmarkServiceInternalDefault to also support the new
    SerializingAdapter interface required for proper ViewModel
    serialization.
---
 .../isis/applib/internal/memento/_Mementos.java    | 33 ++++++++-
 .../internal/memento/_Mementos_MementoDefault.java | 44 +++++++----
 .../applib/services/bookmark/BookmarkService.java  |  1 +
 .../isis/applib/internal/memento/MementosTest.java | 22 +++++-
 ...ObjectFacetDeclarativeInitializingAbstract.java |  7 +-
 .../bookmarks/BookmarkServiceInternalDefault.java  | 85 ++++++++++++++++++++--
 .../services/memento/MementoServiceDefault.java    |  1 +
 7 files changed, 164 insertions(+), 29 deletions(-)

diff --git 
a/core/applib/src/main/java/org/apache/isis/applib/internal/memento/_Mementos.java
 
b/core/applib/src/main/java/org/apache/isis/applib/internal/memento/_Mementos.java
index 291df6f..0864dea 100644
--- 
a/core/applib/src/main/java/org/apache/isis/applib/internal/memento/_Mementos.java
+++ 
b/core/applib/src/main/java/org/apache/isis/applib/internal/memento/_Mementos.java
@@ -19,6 +19,9 @@
 
 package org.apache.isis.applib.internal.memento;
 
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
 import java.util.Set;
 
 import org.apache.isis.applib.services.urlencoding.UrlEncodingService;
@@ -55,6 +58,28 @@ public final class _Mementos {
         public Set<String> keySet();
     }
     
+       // -- SERIALIZER INTERFACE
+       
+    public static interface SerializingAdapter {
+        
+       /**
+        * Converts the value into a Serializable that is write-able to an 
{@link ObjectOutput}.<br/>
+        * Note: write and read are complementary operators.
+        * @param value
+        * @return
+        */
+               public Serializable write(Object value);
+               
+               /**
+                * Converts the value Serializable as read from an {@link 
ObjectInput} into its original (a Pojo).<br/>
+                * Note: write and read are complementary operators.
+                * @param cls
+                * @param value
+                * @return
+                */
+               public <T> T read(Class<T> cls, Serializable value);
+    }    
+    
     // -- CONSTRUCTION
     
     /**
@@ -65,8 +90,8 @@ public final class _Mementos {
      * add to the {@link Memento}, then {@link Memento#asString()} to convert 
to a string format.
      *
      */
-    public static Memento create(UrlEncodingService codec) {
-       return new _Mementos_MementoDefault(codec);
+    public static Memento create(UrlEncodingService codec, SerializingAdapter 
serializer) {
+       return new _Mementos_MementoDefault(codec, serializer);
     }
 
     /**
@@ -77,8 +102,8 @@ public final class _Mementos {
      * in the {@link Memento}. 
      *
      */
-    public static Memento parse(UrlEncodingService codec, final String str) {
-               return _Mementos_MementoDefault.parse(codec, str);
+    public static Memento parse(UrlEncodingService codec, SerializingAdapter 
serializer, final String str) {
+               return _Mementos_MementoDefault.parse(codec, serializer, str);
        
     }
        
diff --git 
a/core/applib/src/main/java/org/apache/isis/applib/internal/memento/_Mementos_MementoDefault.java
 
b/core/applib/src/main/java/org/apache/isis/applib/internal/memento/_Mementos_MementoDefault.java
index d69e5f2..30a4c8e 100644
--- 
a/core/applib/src/main/java/org/apache/isis/applib/internal/memento/_Mementos_MementoDefault.java
+++ 
b/core/applib/src/main/java/org/apache/isis/applib/internal/memento/_Mementos_MementoDefault.java
@@ -23,6 +23,7 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.io.Serializable;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -34,6 +35,7 @@ import org.apache.isis.applib.internal.base._NullSafe;
 import org.apache.isis.applib.internal.collections._Maps;
 import org.apache.isis.applib.internal.collections._Sets;
 import org.apache.isis.applib.internal.memento._Mementos.Memento;
+import org.apache.isis.applib.internal.memento._Mementos.SerializingAdapter;
 import org.apache.isis.applib.services.urlencoding.UrlEncodingService;
 
 /**
@@ -46,28 +48,41 @@ import 
org.apache.isis.applib.services.urlencoding.UrlEncodingService;
 class _Mementos_MementoDefault implements _Mementos.Memento {
        
        private final UrlEncodingService codec;
-       private final Map<String, Object> valuesByKey;
+       private final SerializingAdapter serializer;
        
-       _Mementos_MementoDefault(UrlEncodingService codec) {
-               this(codec, _Maps.newHashMap());
+       private final Map<String, Serializable> valuesByKey;
+       
+       _Mementos_MementoDefault(UrlEncodingService codec, SerializingAdapter 
serializer) {
+               this(codec, serializer, _Maps.newHashMap());
        }
        
-       private _Mementos_MementoDefault(UrlEncodingService codec, Map<String, 
Object> valuesByKey) {
-               Objects.requireNonNull(codec);
-               this.codec = codec;
-               this.valuesByKey = valuesByKey;
+       private _Mementos_MementoDefault(
+                       UrlEncodingService codec,
+                       SerializingAdapter serializer,
+                       Map<String, Serializable> valuesByKey) {
+               
+               this.codec = Objects.requireNonNull(codec);
+               this.serializer = Objects.requireNonNull(serializer);
+               this.valuesByKey = Objects.requireNonNull(valuesByKey);
        }
 
        @Override
        public Memento set(String name, Object value) {
-               valuesByKey.put(name, value);
+               if(value==null) {
+                       return this; //no-op
+               }
+               Objects.requireNonNull(name);
+               valuesByKey.put(name, serializer.write(value));
                return this;
        }
 
        @Override
        public <T> T get(String name, Class<T> cls) {
-               final Object value = valuesByKey.get(name);
-               return _Casts.castToOrElse(value, cls, ()->null);               
+               final Serializable value = valuesByKey.get(name);
+               if(value==null) {
+                       return null;
+               }
+               return serializer.read(cls, value);
        }
 
        @Override
@@ -77,28 +92,25 @@ class _Mementos_MementoDefault implements _Mementos.Memento 
{
        
        @Override
        public String asString() {
-               
                final ByteArrayOutputStream os = new 
ByteArrayOutputStream(16*1024); // 16k initial size
-               
                try(ObjectOutputStream oos = new ObjectOutputStream(os)){
                        oos.writeObject(valuesByKey);
                } catch (Exception e) {
                        throw new IllegalArgumentException("failed to serialize 
memento", e);
                }
-
                return codec.encode(os.toByteArray());
        }
 
        // -- PARSER
        
-       static Memento parse(UrlEncodingService codec, @Nullable String str) {
+       static Memento parse(UrlEncodingService codec, SerializingAdapter 
serializer, @Nullable String str) {
                Objects.requireNonNull(codec);
                if(_NullSafe.isEmpty(str)) {
                        return null;
                }
                try(ObjectInputStream ois = new ObjectInputStream(new 
ByteArrayInputStream(codec.decode(str)))) {
-                       final Map<String, Object> valuesByKey = 
_Casts.uncheckedCast(ois.readObject());
-                       return new _Mementos_MementoDefault(codec, valuesByKey);
+                       final Map<String, Serializable> valuesByKey = 
_Casts.uncheckedCast(ois.readObject());
+                       return new _Mementos_MementoDefault(codec, serializer, 
valuesByKey);
                } catch (Exception e) {
                        throw new IllegalArgumentException("failed to parse 
memento from serialized string", e);
                } 
diff --git 
a/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java
 
b/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java
index cd723a3..7e9a418 100644
--- 
a/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java
+++ 
b/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java
@@ -19,6 +19,7 @@
 package org.apache.isis.applib.services.bookmark;
 
 import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.internal.memento._Mementos.SerializingAdapter;
 
 /**
  * This service enables a serializable &quot;bookmark&quot; to be created for 
an entity.
diff --git 
a/core/applib/src/test/java/org/apache/isis/applib/internal/memento/MementosTest.java
 
b/core/applib/src/test/java/org/apache/isis/applib/internal/memento/MementosTest.java
index d6e5331..6bb3de3 100644
--- 
a/core/applib/src/test/java/org/apache/isis/applib/internal/memento/MementosTest.java
+++ 
b/core/applib/src/test/java/org/apache/isis/applib/internal/memento/MementosTest.java
@@ -23,11 +23,14 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.junit.Assert.assertThat;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Date;
 
+import org.apache.isis.applib.internal.base._Casts;
 import org.apache.isis.applib.internal.memento._Mementos.Memento;
+import org.apache.isis.applib.internal.memento._Mementos.SerializingAdapter;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.urlencoding.UrlEncodingService;
 import 
org.apache.isis.applib.services.urlencoding.UrlEncodingServiceUsingBaseEncodingAbstract;
@@ -44,11 +47,26 @@ public class MementosTest {
 
     UrlEncodingServiceWithCompression serviceWithCompression;
     UrlEncodingServiceUsingBaseEncodingAbstract serviceBaseEncoding;
+    SerializingAdapter serializingAdapter;
 
     @Before
     public void setUp() throws Exception {
        serviceWithCompression = new UrlEncodingServiceWithCompression();
        serviceBaseEncoding = new 
UrlEncodingServiceUsingBaseEncodingAbstract(){};
+       
+       serializingAdapter = new SerializingAdapter() {
+
+                       @Override
+                       public Serializable write(Object value) {
+                               return (Serializable) value;
+                       }
+
+                       @Override
+                       public <T> T read(Class<T> cls, Serializable value) {
+                               return _Casts.castToOrElse(value, cls, 
()->null);
+                       }
+       };
+       
     }
        
        @Test
@@ -62,7 +80,7 @@ public class MementosTest {
        }
        
        private void roundtrip(UrlEncodingService codec) {
-               final Memento memento = _Mementos.create(codec);
+               final Memento memento = _Mementos.create(codec, 
serializingAdapter);
 
                memento.set("someString", "a string");
                memento.set("someStringWithDoubleSpaces", "a  string");
@@ -86,7 +104,7 @@ public class MementosTest {
 
                final String str = memento.asString();
 
-               final Memento memento2 = _Mementos.parse(codec, str);
+               final Memento memento2 = _Mementos.parse(codec, 
serializingAdapter, str);
 
                assertThat(memento2.get("someString", String.class), is("a 
string"));
                assertThat(memento2.get("someStringWithDoubleSpaces", 
String.class), is("a  string"));
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java
index 70a4de4..b497ac8 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java
@@ -24,6 +24,7 @@ import java.util.Set;
 import java.util.UUID;
 
 import org.apache.isis.applib.internal.memento._Mementos;
+import org.apache.isis.applib.internal.memento._Mementos.SerializingAdapter;
 import org.apache.isis.applib.services.urlencoding.UrlEncodingService;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
@@ -63,8 +64,9 @@ public abstract class 
RecreatableObjectFacetDeclarativeInitializingAbstract exte
             final String mementoStr) {
 
        final UrlEncodingService codec = 
servicesInjector.lookupService(UrlEncodingService.class);
+       final SerializingAdapter serializer = 
servicesInjector.lookupService(SerializingAdapter.class);
        
-       final _Mementos.Memento memento = _Mementos.parse(codec, mementoStr);
+       final _Mementos.Memento memento = _Mementos.parse(codec, serializer, 
mementoStr);
        
 //TODO Legacy of ...
 //        final MementoService mementoService = 
servicesInjector.lookupService(MementoService.class);
@@ -113,8 +115,9 @@ public abstract class 
RecreatableObjectFacetDeclarativeInitializingAbstract exte
     public String memento(Object viewModelPojo) {
        
        final UrlEncodingService codec = 
servicesInjector.lookupService(UrlEncodingService.class);
+       final SerializingAdapter serializer = 
servicesInjector.lookupService(SerializingAdapter.class);
        
-       final _Mementos.Memento memento = _Mementos.create(codec);
+               final _Mementos.Memento memento = _Mementos.create(codec, 
serializer);
 
 //TODO Legacy of ...
 //        final MementoService mementoService = 
servicesInjector.lookupService(MementoService.class);
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkServiceInternalDefault.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkServiceInternalDefault.java
index 01c949a..ac4f089 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkServiceInternalDefault.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkServiceInternalDefault.java
@@ -18,16 +18,22 @@
  */
 package org.apache.isis.core.metamodel.services.bookmarks;
 
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.inject.Inject;
 
-import com.google.common.collect.Maps;
-
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.internal.base._Casts;
+import org.apache.isis.applib.internal.collections._Lists;
+import org.apache.isis.applib.internal.collections._Sets;
+import org.apache.isis.applib.internal.memento._Mementos.SerializingAdapter;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.bookmark.BookmarkHolder;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
@@ -36,6 +42,8 @@ import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import 
org.apache.isis.core.metamodel.services.persistsession.PersistenceSessionServiceInternal;
 import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
 
+import com.google.common.collect.Maps;
+
 /**
  * This service enables a serializable &quot;bookmark&quot; to be created for 
an entity.
  *
@@ -48,7 +56,7 @@ import 
org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
         nature = NatureOfService.DOMAIN,
         menuOrder = "" + Integer.MAX_VALUE
 )
-public class BookmarkServiceInternalDefault implements BookmarkService {
+public class BookmarkServiceInternalDefault implements BookmarkService, 
SerializingAdapter {
 
 
     @Programmatic
@@ -164,7 +172,74 @@ public class BookmarkServiceInternalDefault implements 
BookmarkService {
         }
     }
 
-
+    // -- SERIALIZING ADAPTER IMPLEMENTATION
+    
+    @Override
+       public <T> T read(Class<T> cls, Serializable value) {
+       
+       if(Bookmark.class.equals(cls)) {
+               return _Casts.uncheckedCast(value);
+       }
+               
+               if(Bookmark.class.isAssignableFrom(value.getClass())) {
+                       final Bookmark valueBookmark = (Bookmark) value;
+                       return _Casts.uncheckedCast(lookup(valueBookmark));
+               }
+               
+               return _Casts.uncheckedCast(value);
+       }
+       
+       @Override
+       public Serializable write(Object value) {
+        if(isPredefinedSerializable(value.getClass())) {
+            return (Serializable) value;
+        } else {
+            final Bookmark valueBookmark = bookmarkFor(value);
+            return valueBookmark;      
+        }
+       }
+
+       // -- HELPER
+       
+    private final static Set<Class<? extends Serializable>> 
serializableFinalTypes = _Sets.unmodifiable(
+               String.class,
+               Boolean.class, boolean.class,
+               Byte.class, byte.class,
+               Short.class, short.class,
+               Integer.class, int.class,
+               Long.class, long.class,
+               Float.class, float.class,
+               Double.class, double.class
+    );
+    
+    private final static List<Class<? extends Serializable>> serializableTypes 
= _Lists.unmodifiable(
+               BigDecimal.class,
+               BigInteger.class,
+               java.util.Date.class,
+               java.sql.Date.class,
+               Enum.class,
+               Bookmark.class
+    );
+    
+    private static boolean isPredefinedSerializable(final Class<?> cls) {
+       if(!Serializable.class.isAssignableFrom(cls)) {
+               return false;
+       }
+       //[ahuber] any non-scalar values could be problematic, so we are 
careful with wild-cards here
+       if(cls.getName().startsWith("java.time.")) {
+               return true;
+       }
+       if(cls.getName().startsWith("org.joda.time.")) {
+               return true;
+       }
+       if(serializableFinalTypes.contains(cls)) {
+               return true;
+       }
+       return serializableTypes.stream().anyMatch(t->t.isAssignableFrom(cls));
+    }
+       
+       // -- INJECTION
+       
     @javax.inject.Inject
     PersistenceSessionServiceInternal persistenceSessionServiceInternal;
 
@@ -173,5 +248,5 @@ public class BookmarkServiceInternalDefault implements 
BookmarkService {
 
     @Inject
     ServiceRegistry serviceRegistry;
-
+    
 }
diff --git 
a/core/runtime-legacy/src/main/java/org/apache/isis/core/runtime/services/memento/MementoServiceDefault.java
 
b/core/runtime-legacy/src/main/java/org/apache/isis/core/runtime/services/memento/MementoServiceDefault.java
index 52ecbc5..80021c8 100644
--- 
a/core/runtime-legacy/src/main/java/org/apache/isis/core/runtime/services/memento/MementoServiceDefault.java
+++ 
b/core/runtime-legacy/src/main/java/org/apache/isis/core/runtime/services/memento/MementoServiceDefault.java
@@ -168,4 +168,5 @@ public class MementoServiceDefault implements 
MementoService {
     @javax.inject.Inject
     UrlEncodingService urlEncodingService;
 
+    
 }

-- 
To stop receiving notification emails like this one, please contact
ahu...@apache.org.

Reply via email to