From 825193eb4936cd0597de5f3205493058a1bbbc7a Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Mon, 23 Mar 2015 13:17:54 +0100 Subject: [PATCH] Fixed serialization of "Anon" classes. --- .../prism/xjc/PrismContainerArrayList.java | 10 +- .../midpoint/schema/TestConstants.java | 7 +- .../midpoint/schema/TestParseResource.java | 29 ++-- .../midpoint/schema/TestSerialization.java | 140 ++++++++++++++++++ .../schema/src/test/resources/common/role.xml | 13 ++ infra/schema/testng.xml | 1 + .../com/evolveum/midpoint/util/MiscUtil.java | 18 +++ .../midpoint/util/SerializationUtil.java | 6 +- .../schema/xjc/schema/SchemaProcessor.java | 14 +- 9 files changed, 213 insertions(+), 25 deletions(-) create mode 100644 infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSerialization.java diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/xjc/PrismContainerArrayList.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/xjc/PrismContainerArrayList.java index 6c08dc0c411..2f448ef3dfc 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/xjc/PrismContainerArrayList.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/xjc/PrismContainerArrayList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2015 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,10 @@ import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SystemException; + import org.apache.commons.lang.Validate; +import java.io.Serializable; import java.util.AbstractList; import java.util.Collection; import java.util.List; @@ -35,10 +37,14 @@ * * TODO: account for concurrent structural modifications using modCount property */ -public abstract class PrismContainerArrayList extends AbstractList { +public abstract class PrismContainerArrayList extends AbstractList implements Serializable { private PrismContainer container; + // For deserialization + public PrismContainerArrayList() { + } + public PrismContainerArrayList(PrismContainer container) { Validate.notNull(container); this.container = container; diff --git a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestConstants.java b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestConstants.java index 84ccc0bf393..f7a6668c5ab 100644 --- a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestConstants.java +++ b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestConstants.java @@ -49,6 +49,9 @@ public class TestConstants { public static final String USER_ACCOUNT_REF_2_OID = "2f9b9299-6f45-498f-aaaa-000000002222"; public static final String USER_ACCOUNT_REF_3_OID = "2f9b9299-6f45-498f-aaaa-000000003333"; - - + public static final File RESOURCE_FILE = new File(TestConstants.COMMON_DIR, "resource-opendj.xml"); + public static final String RESOURCE_OID = "ef2bc95b-76e0-59e2-86d6-3d4f02d3ffff"; + public static final String RESOURCE_NAMESPACE = "http://midpoint.evolveum.com/xml/ns/public/resource/instance/ef2bc95b-76e0-59e2-86d6-3d4f02d3ffff"; + + public static final File ROLE_FILE = new File(TestConstants.COMMON_DIR, "role.xml"); } diff --git a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseResource.java b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseResource.java index 415cf7e9a81..bc90a40b421 100644 --- a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseResource.java +++ b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseResource.java @@ -76,11 +76,8 @@ */ public class TestParseResource { - public static final File RESOURCE_FILE = new File(TestConstants.COMMON_DIR, "resource-opendj.xml"); - public static final File RESOURCE_NO_XMLNS_FILE = new File(TestConstants.COMMON_DIR, "resource-opendj-no-xmlns.xml"); + public static final File RESOURCE_NO_XMLNS_FILE = new File(TestConstants.COMMON_DIR, "resource-opendj-no-xmlns.xml"); public static final File RESOURCE_SIMPLE_FILE = new File(TestConstants.COMMON_DIR, "resource-opendj-simple.xml"); - private static final String RESOURCE_OID = "ef2bc95b-76e0-59e2-86d6-3d4f02d3ffff"; - private static final String RESOURCE_NAMESPACE = "http://midpoint.evolveum.com/xml/ns/public/resource/instance/ef2bc95b-76e0-59e2-86d6-3d4f02d3ffff"; @BeforeSuite public void setup() throws SchemaException, SAXException, IOException { @@ -97,7 +94,7 @@ public void testParseResourceFile() throws Exception { PrismContext prismContext = PrismTestUtil.getPrismContext(); // WHEN - PrismObject resource = prismContext.parseObject(RESOURCE_FILE); + PrismObject resource = prismContext.parseObject(TestConstants.RESOURCE_FILE); // THEN System.out.println("Parsed resource:"); @@ -133,7 +130,7 @@ public void testParseResourceDom() throws Exception { // WHEN DomParser parserDom = prismContext.getParserDom(); - XNode xnode = parserDom.parse(RESOURCE_FILE); + XNode xnode = parserDom.parse(TestConstants.RESOURCE_FILE); PrismObject resource = prismContext.getXnodeProcessor().parseObject(xnode); // THEN @@ -173,7 +170,7 @@ public void testPrismParseJaxb() throws Exception { JaxbTestUtil jaxbProcessor = JaxbTestUtil.getInstance(); // WHEN - ResourceType resourceType = jaxbProcessor.unmarshalObject(RESOURCE_FILE, ResourceType.class); + ResourceType resourceType = jaxbProcessor.unmarshalObject(TestConstants.RESOURCE_FILE, ResourceType.class); // THEN // HACK: the JAXB parsing methods do not support filter yet, so avoid checking for it @@ -211,7 +208,7 @@ public void testPrismParseJaxbObjectType() throws JAXBException, SchemaException JaxbTestUtil jaxbProcessor = JaxbTestUtil.getInstance(); // WHEN - ObjectType resourceType = jaxbProcessor.unmarshalObject(RESOURCE_FILE, ObjectType.class); + ObjectType resourceType = jaxbProcessor.unmarshalObject(TestConstants.RESOURCE_FILE, ObjectType.class); // THEN // HACK: the JAXB parsing methods do not support filter yet, so avoid checking for it @@ -231,7 +228,7 @@ public void testPrismParseJaxbElement() throws JAXBException, SchemaException, S JaxbTestUtil jaxbProcessor = JaxbTestUtil.getInstance(); // WHEN - JAXBElement jaxbElement = jaxbProcessor.unmarshalElement(RESOURCE_FILE, ResourceType.class); + JAXBElement jaxbElement = jaxbProcessor.unmarshalElement(TestConstants.RESOURCE_FILE, ResourceType.class); ResourceType resourceType = jaxbElement.getValue(); // THEN @@ -252,7 +249,7 @@ public void testPrismParseJaxbElementObjectType() throws JAXBException, SchemaEx JaxbTestUtil jaxbProcessor = JaxbTestUtil.getInstance(); // WHEN - JAXBElement jaxbElement = jaxbProcessor.unmarshalElement(RESOURCE_FILE, ObjectType.class); + JAXBElement jaxbElement = jaxbProcessor.unmarshalElement(TestConstants.RESOURCE_FILE, ObjectType.class); ObjectType resourceType = jaxbElement.getValue(); // THEN @@ -267,7 +264,7 @@ public void testParseResourceRoundtrip() throws Exception { // GIVEN PrismContext prismContext = PrismTestUtil.getPrismContext(); - PrismObject resource = prismContext.parseObject(RESOURCE_FILE); + PrismObject resource = prismContext.parseObject(TestConstants.RESOURCE_FILE); System.out.println("Parsed resource:"); System.out.println(resource.debugDump()); @@ -371,7 +368,7 @@ public void testSchemaRoundtrip() throws Exception { // GIVEN PrismContext prismContext = PrismTestUtil.getPrismContext(); - PrismObject resource = prismContext.parseObject(RESOURCE_FILE); + PrismObject resource = prismContext.parseObject(TestConstants.RESOURCE_FILE); assertResource(resource, true, false, false); @@ -426,7 +423,7 @@ private void assertResourcePrism(PrismObject resource, boolean isS PrismContext prismContext = PrismTestUtil.getPrismContext(); - assertEquals("Wrong oid (prism)", RESOURCE_OID, resource.getOid()); + assertEquals("Wrong oid (prism)", TestConstants.RESOURCE_OID, resource.getOid()); // assertEquals("Wrong version", "42", resource.getVersion()); PrismObjectDefinition resourceDefinition = resource.getDefinition(); assertNotNull("No resource definition", resourceDefinition); @@ -440,7 +437,7 @@ private void assertResourcePrism(PrismObject resource, boolean isS assertPropertyDefinition(resource, "name", PolyStringType.COMPLEX_TYPE, 0, 1); if (!isSimple) { - assertPropertyValue(resource, "namespace", RESOURCE_NAMESPACE); + assertPropertyValue(resource, "namespace", TestConstants.RESOURCE_NAMESPACE); assertPropertyDefinition(resource, "namespace", DOMUtil.XSD_ANYURI, 0, 1); } @@ -524,9 +521,9 @@ private void assertResourcePrism(PrismObject resource, boolean isS } private void assertResourceJaxb(ResourceType resourceType, boolean isSimple) throws SchemaException { - assertEquals("Wrong oid (JAXB)", RESOURCE_OID, resourceType.getOid()); + assertEquals("Wrong oid (JAXB)", TestConstants.RESOURCE_OID, resourceType.getOid()); assertEquals("Wrong name (JAXB)", PrismTestUtil.createPolyStringType("Embedded Test OpenDJ"), resourceType.getName()); - String expectedNamespace = RESOURCE_NAMESPACE; + String expectedNamespace = TestConstants.RESOURCE_NAMESPACE; if (isSimple) { expectedNamespace = MidPointConstants.NS_RI; } diff --git a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSerialization.java b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSerialization.java new file mode 100644 index 00000000000..d231612c368 --- /dev/null +++ b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSerialization.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015 Evolveum + * + * Licensed 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 com.evolveum.midpoint.schema; + +import static org.testng.AssertJUnit.assertNull; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; + +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.util.PrismTestUtil; +import com.evolveum.midpoint.schema.constants.MidPointConstants; +import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.util.PrettyPrinter; +import com.evolveum.midpoint.util.SerializationUtil; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; + +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Test; +import org.xml.sax.SAXException; + +import java.io.File; +import java.io.IOException; +import java.util.List; + + +/** + * @author semancik + * + */ +public class TestSerialization { + + + + @BeforeSuite + public void setup() throws SchemaException, SAXException, IOException { + PrettyPrinter.setDefaultNamespacePrefix(MidPointConstants.NS_MIDPOINT_PUBLIC_PREFIX); + PrismTestUtil.resetPrismContext(MidPointPrismContextFactory.FACTORY); + } + + + @Test + public void testSerializeResource() throws Exception { + System.out.println("===[ testSerializeResource ]==="); + + serializationRoundTrip(TestConstants.RESOURCE_FILE); + } + + @Test + public void testSerializeUser() throws Exception { + System.out.println("===[ testSerializeUser ]==="); + + serializationRoundTrip(TestConstants.USER_FILE); + } + + @Test + public void testSerializeRole() throws Exception { + System.out.println("===[ testSerializeRole ]==="); + + PrismContext prismContext = PrismTestUtil.getPrismContext(); + + PrismObject parsedObject = prismContext.parseObject(TestConstants.ROLE_FILE); + + System.out.println("Parsed object:"); + System.out.println(parsedObject.debugDump()); + + RoleType parsedRoleType = parsedObject.asObjectable(); + PolicyConstraintsType policyConstraints = parsedRoleType.getPolicyConstraints(); + List minAssignees = policyConstraints.getMinAssignees(); + minAssignees.iterator().next(); + + // WHEN + serializationRoundTripPrismObject(parsedObject); + serializationRoundTripObjectType(parsedRoleType); + + // WHEN + String serializedMinAssignees = SerializationUtil.toString(minAssignees); + List deserializedMinAssignees = SerializationUtil.fromString(serializedMinAssignees); + assertTrue("minAssignees mismatch: expected "+minAssignees+", was "+deserializedMinAssignees, MiscUtil.listEquals(minAssignees, deserializedMinAssignees)); + } + + private void serializationRoundTrip(File file) throws Exception { + PrismContext prismContext = PrismTestUtil.getPrismContext(); + + PrismObject parsedObject = prismContext.parseObject(file); + + System.out.println("Parsed object:"); + System.out.println(parsedObject.debugDump()); + + serializationRoundTripPrismObject(parsedObject); + serializationRoundTripObjectType(parsedObject.asObjectable()); + } + + private void serializationRoundTripPrismObject(PrismObject parsedObject) throws Exception { + + // WHEN + String serializedObject = SerializationUtil.toString(parsedObject); + + // THEN + PrismObject deserializedObject = SerializationUtil.fromString(serializedObject); + + System.out.println("Deserialized object (PrismObject):"); + System.out.println(deserializedObject.debugDump()); + + ObjectDelta diff = parsedObject.diff(deserializedObject); + assertTrue("Something changed in serialization of "+parsedObject+" (PrismObject): "+diff, diff.isEmpty()); + } + + private void serializationRoundTripObjectType(O parsedObject) throws Exception { + + // WHEN + String serializedObject = SerializationUtil.toString(parsedObject); + + // THEN + O deserializedObject = SerializationUtil.fromString(serializedObject); + + System.out.println("Deserialized object (ObjectType):"); + System.out.println(deserializedObject.asPrismObject().debugDump()); + + ObjectDelta diff = parsedObject.asPrismObject().diff(deserializedObject.asPrismObject()); + assertTrue("Something changed in serializetion of "+parsedObject+" (ObjectType): "+diff, diff.isEmpty()); + } + +} diff --git a/infra/schema/src/test/resources/common/role.xml b/infra/schema/src/test/resources/common/role.xml index e8a157c2d31..8a4a06fd5b1 100644 --- a/infra/schema/src/test/resources/common/role.xml +++ b/infra/schema/src/test/resources/common/role.xml @@ -27,4 +27,17 @@ midpoint.oid2ort(user.getOid()) + + + + report + 2 + + + 1 + + + unbounded + + diff --git a/infra/schema/testng.xml b/infra/schema/testng.xml index d11f0900bc4..934b3228bf5 100644 --- a/infra/schema/testng.xml +++ b/infra/schema/testng.xml @@ -44,6 +44,7 @@ + diff --git a/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java b/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java index 8614be3f5e7..74273b7362f 100644 --- a/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java +++ b/infra/util/src/main/java/com/evolveum/midpoint/util/MiscUtil.java @@ -82,6 +82,24 @@ public static Collection unionExtends(Collection.. return resultSet; } + public static boolean listEquals(List a, List b) { + if (a == null && b == null) { + return true; + } + if (a == null || b == null) { + return false; + } + if (a.size() != b.size()) { + return false; + } + for (int i = 0; i < a.size(); i++) { + if (!a.get(i).equals(b.get(i))) { + return false; + } + } + return true; + } + public static boolean unorderedCollectionEquals(Collection a, Collection b) { Comparator comparator = new Comparator() { @Override diff --git a/infra/util/src/main/java/com/evolveum/midpoint/util/SerializationUtil.java b/infra/util/src/main/java/com/evolveum/midpoint/util/SerializationUtil.java index a3f5739c8c4..c4681039da8 100644 --- a/infra/util/src/main/java/com/evolveum/midpoint/util/SerializationUtil.java +++ b/infra/util/src/main/java/com/evolveum/midpoint/util/SerializationUtil.java @@ -35,15 +35,15 @@ */ public class SerializationUtil { - public static Object fromString(String string) throws IOException, ClassNotFoundException { + public static T fromString(String string) throws IOException, ClassNotFoundException { byte[] data = Base64.decodeBase64(string); ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data)); Object object = objectInputStream.readObject(); objectInputStream.close(); - return object; + return (T)object; } - public static String toString(Serializable object) throws IOException { + public static String toString(Object object) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(object); diff --git a/tools/xjc-plugin/src/main/java/com/evolveum/midpoint/schema/xjc/schema/SchemaProcessor.java b/tools/xjc-plugin/src/main/java/com/evolveum/midpoint/schema/xjc/schema/SchemaProcessor.java index 2f996b36c3a..68e61fe219b 100644 --- a/tools/xjc-plugin/src/main/java/com/evolveum/midpoint/schema/xjc/schema/SchemaProcessor.java +++ b/tools/xjc-plugin/src/main/java/com/evolveum/midpoint/schema/xjc/schema/SchemaProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2015 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -68,6 +68,7 @@ import com.sun.xml.xsom.XSSchema; import com.sun.xml.xsom.XSSchemaSet; import com.sun.xml.xsom.XSType; + import org.apache.commons.lang.Validate; import org.jvnet.jaxb2_commons.lang.Equals; import org.jvnet.jaxb2_commons.lang.HashCode; @@ -85,6 +86,8 @@ import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.XmlType; import javax.xml.namespace.QName; + +import java.io.Serializable; import java.io.StringWriter; import java.lang.reflect.Field; import java.util.ArrayList; @@ -1246,6 +1249,7 @@ private JDefinedClass createFieldReferenceGetterListAnon(JFieldVar field, ClassO throw new RuntimeException(ex.getMessage(), ex); } + anonymous._implements(Serializable.class); anonymous._extends(clazz); JMethod constructor = anonymous.constructor(JMod.PUBLIC); constructor.param(CLASS_MAP.get(PrismReference.class), REFERENCE_LOCAL_VARIABLE_NAME); @@ -1592,8 +1596,8 @@ private JDefinedClass createFieldContainerGetterListAnon(JFieldVar field, ClassO throw new RuntimeException(ex.getMessage(), ex); } + anonymous._implements(Serializable.class); anonymous._extends(clazz); - JMethod constructor = anonymous.constructor(JMod.PUBLIC); JClass list = (JClass) field.type(); JClass listType = list.getTypeParameters().get(0); @@ -1601,11 +1605,17 @@ private JDefinedClass createFieldContainerGetterListAnon(JFieldVar field, ClassO JClass container = CLASS_MAP.get(PrismContainer.class); container.narrow(listType); + JMethod constructor = anonymous.constructor(JMod.PUBLIC); constructor.param(container, "container"); JBlock constructorBody = constructor.body(); JInvocation invocation = constructorBody.invoke("super"); invocation.arg(constructor.listParams()[0]); + // Default constructor, for deserialization + JMethod defaultConstructor = anonymous.constructor(JMod.PUBLIC); + JBlock defaultConstructorBody = defaultConstructor.body(); + defaultConstructorBody.invoke("super"); + JMethod createItem = anonymous.method(JMod.PROTECTED, listType, "createItem"); createItem.annotate(CLASS_MAP.get(Override.class)); createItem.param(CLASS_MAP.get(PrismContainerValue.class), "value");