You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by gr...@apache.org on 2020/05/28 11:48:24 UTC

[royale-asjs] 01/05: AMF improvements: Coverage for ignoring custom namespaces and also cases where Transient fields are still deserialized. They are only skipped during local serialization.

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

gregdove pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git

commit db0995ea20121a7e0490627592367473248266f9
Author: greg-dove <gr...@gmail.com>
AuthorDate: Thu May 28 16:36:51 2020 +1200

    AMF improvements: Coverage for ignoring custom namespaces and also cases where Transient fields are still deserialized. They are only skipped during local serialization.
---
 .../royale/net/remoting/amf/AMFBinaryData.as       |  41 +++++---
 .../network/AMFBinaryDataTesterTest.as             | 109 ++++++++++++++++++++-
 .../flexUnitTests/network/support/TestClass6.as    |  72 ++++++++++++++
 .../flexUnitTests/network/support/TestClass7a.as   |  51 ++++++++++
 .../flexUnitTests/network/support/TestClass7b.as   |  49 +++++++++
 .../flexUnitTests/network/support/testnamespace.as |  26 +++++
 6 files changed, 334 insertions(+), 14 deletions(-)

diff --git a/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFBinaryData.as b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFBinaryData.as
index 3eb6955..89350f4 100644
--- a/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFBinaryData.as
+++ b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFBinaryData.as
@@ -499,6 +499,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		var l:uint;
 		var metas:Array;
 		var exclude:Boolean;
+		var transient:Boolean;
 		var fieldName:String;
 		const into:Array = localTraits.props;
 		
@@ -509,9 +510,11 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			if (fieldName.indexOf('::') != -1) continue;
 			var field:Object = fieldSet[fieldName];
 			exclude = false;
+			transient = false;
+			var alreadyPresent:Boolean = into.indexOf(fieldName) != -1 ;
 			if (asAccessors) {
 				exclude = field.access != 'readwrite';
-				if (exclude && into.indexOf(fieldName) == -1) { //<-- if at some level we already have read-write access, then that wins
+				if (exclude && !alreadyPresent) { //<-- if at some level we already have read-write access, then that wins
 					//check: does it combine to provide 'readwrite' permissions via accessChecks through inheritance chain
 					if (accessChecks[fieldName] && accessChecks[fieldName] != field.access) {
 						//readonly or writeonly overridde at one level and different at another == readwrite
@@ -524,21 +527,18 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 					}
 				}
 			}
-			if (!exclude && excludeTransient && field.metadata != null) {
-				//exclude anything marked as Transient
+			//if a subclass override does not redeclare the field as transient, then it is already considered explicitly 'non-transient'
+			if (!exclude && !alreadyPresent && excludeTransient && field.metadata != null) {
+				//we need to mark Transient fields as special case
 				metas = field.metadata();
 				l = metas.length;
 				while (l--) {
 					if (metas[l].name == 'Transient') {
-						exclude = true;
+						transient = true;
+						Traits.markTransient(fieldName, localTraits);
+						break;
 					}
 				}
-				if (exclude && into.indexOf(fieldName) != -1) {
-					//?possible case where it is marked transient on an ancestor but not in a subclass override
-					//it will not have been excluded when processing the subclass, which occurs first, so remove it now
-					//@todo untested : check this scenario, assume it should be removed
-					into.splice(into.indexOf(fieldName), 1);
-				}
 			}
 			if (!exclude) {
 				//set up null/undefined value lookups for undefined field values (when encoding)
@@ -554,7 +554,10 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 				} else {
 					nullValues[fieldName] = null;
 				}
-				into.push(fieldName);
+				if (alreadyPresent) {
+					into.splice(into.indexOf(fieldName), 1);
+				}
+				if (!transient) into.push(fieldName);
 				if (asAccessors) {
 					localTraits.getterSetters[fieldName] = Traits.createInstanceAccessorGetterSetter(fieldName);
 				} else {
@@ -610,6 +613,9 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 					classInfo = c.constructor.superClass_.ROYALE_CLASS_INFO;
 					c = c.constructor.superClass_;
 				}
+				//sometimes flash native seriazliation double-counts props and outputs some props data twice.
+				//this can happen with overrides (it was noticed with Transient overrides)
+				//it may mean that js amf output can sometimes be more compact, but should always deserialize to the same result.
 				localTraits.count = localTraits.props.length;
 				//not required, but useful when testing:
 				localTraits.props.sort();
@@ -632,7 +638,6 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			}
 			//not required, but useful when testing:
 			localTraits.props.sort();
-			
 		}
 		return localTraits;
 	}
@@ -1102,7 +1107,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 				for (var i:uint = 0; i < l; i++) {
 					var fieldValue:* = readObject();
 					var prop:String = decodedTraits.props[i];
-					hasProp = localTraits &&  (localTraits.hasProp(prop) || localTraits.isDynamic);
+					hasProp = localTraits &&  (localTraits.hasProp(prop) || localTraits.isDynamic || localTraits.isTransient(prop));
 					if (hasProp) {
 						localTraits.getterSetters[prop].setValue(obj, fieldValue);
 					} else {
@@ -1319,6 +1324,11 @@ class Traits {
 			}
 		};
 	}
+
+	public static function markTransient(fieldName:String, traits:Traits):void{
+		if (!traits.transients) traits.transients={};
+		traits.transients[fieldName] = true;
+	}
 	
 	private static var _emtpy_object:Traits;
 	
@@ -1362,10 +1372,15 @@ class Traits {
 	public var nullValues:Object = {};
 	
 	public var getterSetters:Object = {};
+	public var transients:Object ;
 	
 	public function hasProp(prop:String):Boolean {
 		return props.indexOf(prop) != -1;
 	}
+
+	public function isTransient(prop:String):Boolean {
+		return transients && prop in transients;
+	}
 	
 	public function toString():String {
 		if (goog.DEBUG) {
diff --git a/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMFBinaryDataTesterTest.as b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMFBinaryDataTesterTest.as
index 144d034..1cca14c 100644
--- a/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMFBinaryDataTesterTest.as
+++ b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMFBinaryDataTesterTest.as
@@ -27,7 +27,9 @@ package flexUnitTests.network
     import flexUnitTests.network.support.TestClass3;
     import flexUnitTests.network.support.TestClass4;
     import flexUnitTests.network.support.DynamicTestClass;
-    
+    import flexUnitTests.network.support.TestClass6;
+    import flexUnitTests.network.support.TestClass7a;
+    import flexUnitTests.network.support.TestClass7b;
     import org.apache.royale.test.asserts.*;
     
     import org.apache.royale.net.remoting.amf.AMFBinaryData;
@@ -532,6 +534,111 @@ package flexUnitTests.network
             //javascript toXMLString pretty printing does not match exactly flash...
             assertTrue( xml.toXMLString() === xml2.toXMLString(), "XML round-tripping failed");
         }
+
+
+        [Test]
+        public function testWithCustomNS():void
+        {
+            var ba:AMFBinaryData = new AMFBinaryData();
+            var test:TestClass6 = new TestClass6();
+            ba.writeObject(test);
+            ba.position = 0;
+            assertEquals(ba.length, 50, 'unexpected serialized content with custom namespaces');
+            //cover variation in order
+            const validOptions:Array = [
+                '0a23010b6d79566172156d794163636573736f7206177075626c69634d79566172061f7075626c6963206163636573736f72',
+                '0a2301156d794163636573736f720b6d79566172061f7075626c6963206163636573736f7206177075626c69634d79566172'
+            ];
+
+            assertTrue(validOptions.indexOf(getBytesOut(ba)) != -1, 'unexpected byte content with custom namespace content');
+
+           /* var restored:Object = ba.readObject();
+
+            var json:String = JSON.stringify(restored)*/
+            //order may be different... need json object check here for: {"myAccessor":"public accessor","myVar":"publicMyVar"}
+        }
+
+        [Test]
+        public function testTransientAndBindable():void{
+            var ba:AMFBinaryData = new AMFBinaryData();
+            registerClassAlias('TestClass7a', TestClass7a);
+            registerClassAlias('TestClass7b', TestClass7b);
+            var test1:TestClass7a = new TestClass7a();
+            test1.something = 'whatever';
+            ba.writeObject(test1);
+
+            ba.position = 0;
+
+            var retrieved:Object = ba.readObject();
+
+            assertTrue(retrieved is TestClass7a, 'unexpected deserialization');
+
+            var test2:TestClass7b = new TestClass7b();
+            test1.something = 'whatever';
+            ba.length = 0;
+            ba.writeObject(test2);
+
+            ba.position = 0;
+            retrieved = ba.readObject();
+
+            assertTrue(retrieved is TestClass7b, 'unexpected deserialization');
+
+        }
+
+
+        [Test]
+        public function testTransientDeserialized():void{
+            //if a transient field is already serialized, then we do deserialize it
+            //this means it can be sent from the server (for example) but is not sent to the server
+
+            //to test this we will use TestClass7b (where 'something' is not Transient) which will serialize the 'something' field with an alias that matches
+            //a subsequent deserialization to a TestClass7a instance (where 'something' is Transient);
+            //the expected result will be that the Transient field is still deserialized
+
+            var ba:AMFBinaryData = new AMFBinaryData();
+            registerClassAlias('TestClass7a', TestClass7b);
+            var test1:TestClass7b = new TestClass7b();
+            test1.something = 'something interesting';
+            ba.length = 0;
+            //non-transient inbound:
+            ba.writeObject(test1);
+
+            //The bytes for the above can differ between swf and js. 54 vs. 57 bytes length
+            //It is possible to correct that. But it is the swf output that is serializing the 'something' field twice
+            // (second time is string ref for both field and value, so quite compact, but still unnecessary)
+            //so not trying to match that exactly, because it is redundant data.
+
+            ba.position = 0;
+
+            //read it back as TestClass7a
+            registerClassAlias('TestClass7a', TestClass7a);
+
+            var retrieved:Object = ba.readObject();
+
+
+            assertTrue(retrieved is TestClass7a, 'unexpected deserialization');
+            assertEquals(retrieved.something , 'something interesting', 'unexpected deserialization');
+            assertEquals(retrieved.test , 'test', 'unexpected deserialization');
+
+            //this time round it won't be read out because it is Transient for serialization/inbound:
+            ba.position = 0;
+            ba.length=0;
+            ba.writeObject(retrieved);
+            ba.position = 0;
+            retrieved = ba.readObject();
+            assertTrue(retrieved is TestClass7a, 'unexpected deserialization');
+            assertEquals(retrieved.something , null, 'unexpected deserialization');
+            assertEquals(retrieved.test , 'test', 'unexpected deserialization');
+        }
+
+
+        private function getBytesOut(bytes:AMFBinaryData):String{
+            var out:Array = [];
+            for each(var byte:uint in bytes) {
+                out.push(('0'+byte.toString(16)).substr(-2));
+            }
+            return out.join('');
+        }
         
     }
 }
diff --git a/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/TestClass6.as b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/TestClass6.as
new file mode 100644
index 0000000..42a1e3c
--- /dev/null
+++ b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/TestClass6.as
@@ -0,0 +1,72 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 flexUnitTests.network.support
+{
+   
+    import flexUnitTests.network.support.testnamespace;
+    
+    /**
+     * @royalesuppresspublicvarwarning
+     */
+    public class TestClass6
+    {
+        //Note: do not change this test class unless you change the related tests to
+        //support any changes that might appear when testing reflection into it
+        
+        public function TestClass6()
+        {
+        
+        }
+        
+        
+        public var myVar:String = 'publicMyVar';
+        
+        testnamespace var myVar:String = 'testnamespaceMyVar';
+        
+        public function myMethod():String{
+            return 'public myMethod';
+        }
+    
+        testnamespace function myMethod():String{
+            return 'testnamespace myMethod';
+        }
+    
+        private var _v:String = 'public accessor';
+        public function get myAccessor():String{
+            return _v;
+        }
+    
+        public function set myAccessor(value:String):void{
+            _v = value;
+        }
+        
+        private var _v2:String = 'testnamespace accessor';
+        testnamespace function get myAccessor():String{
+            return _v2;
+        }
+    
+        testnamespace function set myAccessor(value:String):void{
+            _v2 = value;
+        }
+        
+        
+    }
+    
+    
+}
diff --git a/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/TestClass7a.as b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/TestClass7a.as
new file mode 100644
index 0000000..db6ec8b
--- /dev/null
+++ b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/TestClass7a.as
@@ -0,0 +1,51 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 flexUnitTests.network.support
+{
+   
+    import flexUnitTests.network.support.testnamespace;
+    
+    /**
+     * @royalesuppresspublicvarwarning
+     */
+    public class TestClass7a
+    {
+        //Note: do not change this test class unless you change the related tests to
+        //support any changes that might appear when testing reflection into it
+        
+        public function TestClass7a()
+        {
+        
+        }
+
+        public var test:String = 'test';
+        
+        protected var _something:String;
+        [Transient]
+        public function get something():String{
+            return _something;
+        }
+        public function set something(value:String):void{
+            _something = value;
+        }
+        
+    }
+    
+    
+}
diff --git a/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/TestClass7b.as b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/TestClass7b.as
new file mode 100644
index 0000000..39b5f7d
--- /dev/null
+++ b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/TestClass7b.as
@@ -0,0 +1,49 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 flexUnitTests.network.support
+{
+   
+    import flexUnitTests.network.support.testnamespace;
+    
+    /**
+     * @royalesuppresspublicvarwarning
+     */
+    public class TestClass7b extends TestClass7a
+    {
+        //Note: do not change this test class unless you change the related tests to
+        //support any changes that might appear when testing reflection into it
+        
+        public function TestClass7b()
+        {
+        
+        }
+        
+
+        [Bindable]
+        override public function get something():String{
+            return _something;
+        }
+        override public function set something(value:String):void{
+            _something = value;
+        }
+        
+    }
+    
+    
+}
diff --git a/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/testnamespace.as b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/testnamespace.as
new file mode 100644
index 0000000..3a552b8
--- /dev/null
+++ b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/support/testnamespace.as
@@ -0,0 +1,26 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 flexUnitTests.network.support
+{
+    
+    
+
+    public namespace testnamespace = 'http://testnamespace.com/network';
+   
+}