Repository: metamodel
Updated Branches:
  refs/heads/master 7c8628a07 -> 583e32aed


METAMODEL-1160/METAMODEL-1163 Deserializing legacy schema objects closes 
apache/metamodel#160


Project: http://git-wip-us.apache.org/repos/asf/metamodel/repo
Commit: http://git-wip-us.apache.org/repos/asf/metamodel/commit/583e32ae
Tree: http://git-wip-us.apache.org/repos/asf/metamodel/tree/583e32ae
Diff: http://git-wip-us.apache.org/repos/asf/metamodel/diff/583e32ae

Branch: refs/heads/master
Commit: 583e32aed942a1b091891459b068a2f8c4d17602
Parents: 7c8628a
Author: Kasper Sørensen <[email protected]>
Authored: Thu Aug 31 19:57:15 2017 +0200
Committer: Dennis Du Krøger <[email protected]>
Committed: Thu Aug 31 19:57:15 2017 +0200

----------------------------------------------------------------------
 CHANGES.md                                      |   2 +
 .../metamodel/schema/ImmutableRelationship.java |  20 +++++
 .../metamodel/schema/MutableRelationship.java   |  18 +++++
 .../LegacyDeserializationObjectInputStream.java |  18 +++++
 .../org/apache/metamodel/MetaModelTestCase.java |   2 +-
 .../metamodel/schema/ImmutableSchemaTest.java   |  66 +++++++++++++---
 .../metamodel/schema/MutableSchemaTest.java     |  51 +++++++++++-
 .../metamodel-4.6.0-immutableschema-etc.ser     | Bin 0 -> 1851 bytes
 .../metamodel-4.6.0-mutableschema-etc.ser       | Bin 0 -> 1854 bytes
 .../java/org/apache/metamodel/csv/CsvTable.java |  23 +++++-
 .../org/apache/metamodel/csv/CsvTableTest.java  |  78 +++++++++++++++++++
 .../test/resources/MetaModel-4.6.0-CsvTable.ser | Bin 0 -> 1407 bytes
 12 files changed, 264 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/CHANGES.md
----------------------------------------------------------------------
diff --git a/CHANGES.md b/CHANGES.md
index 57cf422..a0692ca 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -12,6 +12,8 @@
  * [METAMODEL-1144] - Optimized evaluation of conditional client-side JOIN 
statements.
  * [METAMODEL-1145] - Fixed bug with modelling JDBC table relationships when 
there are multiple keys involved in the relationship.
  * [METAMODEL-1151] - Added DataContextFactory classes for instantiating 
DataContexts of many types based on properties.
+ * [METAMODEL-1160] - Fixed bug when deserializing v4.x CsvTable objects
+ * [METAMODEL-1163] - Fixed bug when deserializing v4.x MutableRelationship 
and ImmutableRelationship objects
 
 ### Apache MetaModel 4.6.0
 

http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/core/src/main/java/org/apache/metamodel/schema/ImmutableRelationship.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/metamodel/schema/ImmutableRelationship.java 
b/core/src/main/java/org/apache/metamodel/schema/ImmutableRelationship.java
index 7ca8fe9..0d4d1df 100644
--- a/core/src/main/java/org/apache/metamodel/schema/ImmutableRelationship.java
+++ b/core/src/main/java/org/apache/metamodel/schema/ImmutableRelationship.java
@@ -18,10 +18,16 @@
  */
 package org.apache.metamodel.schema;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectInputStream.GetField;
 import java.io.Serializable;
+import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import org.apache.metamodel.util.LegacyDeserializationObjectInputStream;
+
 public final class ImmutableRelationship extends AbstractRelationship 
implements Serializable {
 
        private static final long serialVersionUID = 1L;
@@ -79,4 +85,18 @@ public final class ImmutableRelationship extends 
AbstractRelationship implements
        public List<Column> getForeignColumns() {
                return foreignColumns;
        }
+
+    private void readObject(ObjectInputStream stream) throws IOException, 
ClassNotFoundException {
+        final GetField getFields = stream.readFields();
+        Object primaryColumns = getFields.get("primaryColumns", null);
+        Object foreignColumns = getFields.get("foreignColumns", null);
+        if (primaryColumns instanceof Column[] && foreignColumns instanceof 
Column[]) {
+            primaryColumns = Arrays.<Column> asList((Column[]) primaryColumns);
+            foreignColumns = Arrays.<Column> asList((Column[]) foreignColumns);
+        }
+        
LegacyDeserializationObjectInputStream.setField(ImmutableRelationship.class, 
this, "primaryColumns",
+                primaryColumns);
+        
LegacyDeserializationObjectInputStream.setField(ImmutableRelationship.class, 
this, "foreignColumns",
+                foreignColumns);
+    }
 }

http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/core/src/main/java/org/apache/metamodel/schema/MutableRelationship.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/metamodel/schema/MutableRelationship.java 
b/core/src/main/java/org/apache/metamodel/schema/MutableRelationship.java
index 3ea624c..47206cd 100644
--- a/core/src/main/java/org/apache/metamodel/schema/MutableRelationship.java
+++ b/core/src/main/java/org/apache/metamodel/schema/MutableRelationship.java
@@ -18,10 +18,15 @@
  */
 package org.apache.metamodel.schema;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectInputStream.GetField;
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
+import org.apache.metamodel.util.LegacyDeserializationObjectInputStream;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -134,4 +139,17 @@ public class MutableRelationship extends 
AbstractRelationship implements
                return _foreignColumns;
        }
 
+    private void readObject(ObjectInputStream stream) throws IOException, 
ClassNotFoundException {
+        final GetField getFields = stream.readFields();
+        Object primaryColumns = getFields.get("_primaryColumns", null);
+        Object foreignColumns = getFields.get("_foreignColumns", null);
+        if (primaryColumns instanceof Column[] && foreignColumns instanceof 
Column[]) {
+            primaryColumns = Arrays.<Column> asList((Column[]) primaryColumns);
+            foreignColumns = Arrays.<Column> asList((Column[]) foreignColumns);
+        }
+        
LegacyDeserializationObjectInputStream.setField(MutableRelationship.class, 
this, "_primaryColumns",
+                primaryColumns);
+        
LegacyDeserializationObjectInputStream.setField(MutableRelationship.class, 
this, "_foreignColumns",
+                foreignColumns);
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java
 
b/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java
index 95fad92..c39f27a 100644
--- 
a/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java
+++ 
b/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java
@@ -45,6 +45,24 @@ public class LegacyDeserializationObjectInputStream extends 
ObjectInputStream {
     private static final Logger logger = 
LoggerFactory.getLogger(LegacyDeserializationObjectInputStream.class);
 
     /**
+     * Utility method for setting a field in a class
+     * 
+     * @param cls
+     * @param fieldName
+     * @param value
+     */
+    public static void setField(Class<?> cls, Object instance, String 
fieldName, Object value) {
+        try {
+            final Field field = cls.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            field.set(instance, value);
+        } catch (ReflectiveOperationException e) {
+            throw new IllegalStateException(
+                    "Unable to assign field '" + cls.getSimpleName() + '.' + 
fieldName + "' to value: " + value, e);
+        }
+    }
+
+    /**
      * Implementation of the new {@link FunctionType} and
      * {@link AggregateFunction} interfaces which still adheres to the
      * constant/enum values of the old FunctionType definition. While

http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/core/src/test/java/org/apache/metamodel/MetaModelTestCase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/metamodel/MetaModelTestCase.java 
b/core/src/test/java/org/apache/metamodel/MetaModelTestCase.java
index 56d57c8..75cc1b5 100644
--- a/core/src/test/java/org/apache/metamodel/MetaModelTestCase.java
+++ b/core/src/test/java/org/apache/metamodel/MetaModelTestCase.java
@@ -86,7 +86,7 @@ public abstract class MetaModelTestCase extends TestCase {
      * <li>Views: The ProjectContributor view</li>
      * </ul>
      */
-    protected Schema getExampleSchema() {
+    public static Schema getExampleSchema() {
         MutableSchema schema = new MutableSchema("MetaModelSchema");
 
         MutableTable table1 = new MutableTable(TABLE_CONTRIBUTOR, 
TableType.TABLE, schema);

http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/core/src/test/java/org/apache/metamodel/schema/ImmutableSchemaTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/metamodel/schema/ImmutableSchemaTest.java 
b/core/src/test/java/org/apache/metamodel/schema/ImmutableSchemaTest.java
index 16c74f9..b127f8e 100644
--- a/core/src/test/java/org/apache/metamodel/schema/ImmutableSchemaTest.java
+++ b/core/src/test/java/org/apache/metamodel/schema/ImmutableSchemaTest.java
@@ -18,18 +18,64 @@
  */
 package org.apache.metamodel.schema;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Arrays;
+
 import org.apache.metamodel.MetaModelTestCase;
+import org.apache.metamodel.util.LegacyDeserializationObjectInputStream;
+import org.junit.Test;
+
+public class ImmutableSchemaTest {
+
+    @Test
+    public void testConstructor() throws Exception {
+        Schema mutableSchema = MetaModelTestCase.getExampleSchema();
+        assertTrue(mutableSchema instanceof MutableSchema);
+
+        ImmutableSchema immutableSchema = new ImmutableSchema(mutableSchema);
+
+        assertEquals(mutableSchema.getRelationshipCount(), 
immutableSchema.getRelationshipCount());
+
+        assertEquals(immutableSchema, mutableSchema);
+    }
+
+    @Test
+    public void testDeserializeOldFormat() throws Exception {
+        final File file = new 
File("src/test/resources/metamodel-4.6.0-immutableschema-etc.ser");
+        assertTrue(file.exists());
+
+        try (final FileInputStream in = new FileInputStream(file)) {
+            final LegacyDeserializationObjectInputStream ois = new 
LegacyDeserializationObjectInputStream(in);
+            final Object obj = ois.readObject();
+            assertTrue(obj instanceof ImmutableSchema);
+            ois.close();
+
+            final ImmutableSchema sch = (ImmutableSchema) obj;
+            assertEquals("schema", sch.getName());
+
+            assertEquals(2, sch.getTableCount());
 
-public class ImmutableSchemaTest extends MetaModelTestCase {
+            final Table table1 = sch.getTable(0);
+            assertTrue(table1 instanceof ImmutableTable);
+            assertEquals("t1", table1.getName());
+            assertEquals(Arrays.asList("t1_c1", "t1_c2"), 
table1.getColumnNames());
+            assertEquals(1, table1.getRelationshipCount());
 
-       public void testConstructor() throws Exception {
-               Schema mutableSchema = getExampleSchema();
-               assertTrue(mutableSchema instanceof MutableSchema);
+            final Table table2 = sch.getTable(1);
+            assertTrue(table2 instanceof ImmutableTable);
+            assertEquals("t2", table2.getName());
+            assertEquals(Arrays.asList("t2_c1"), table2.getColumnNames());
+            assertEquals(1, table2.getRelationshipCount());
 
-               ImmutableSchema immutableSchema = new 
ImmutableSchema(mutableSchema);
-               
-               assertEquals(mutableSchema.getRelationshipCount(), 
immutableSchema.getRelationshipCount());
-               
-               assertEquals(immutableSchema, mutableSchema);
-       }
+            final Relationship rel1 = 
table1.getRelationships().iterator().next();
+            final Relationship rel2 = 
table2.getRelationships().iterator().next();
+            assertSame(rel1, rel2);
+            assertTrue(rel1 instanceof ImmutableRelationship);
+        }
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/core/src/test/java/org/apache/metamodel/schema/MutableSchemaTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/metamodel/schema/MutableSchemaTest.java 
b/core/src/test/java/org/apache/metamodel/schema/MutableSchemaTest.java
index cc313ee..f68d13d 100644
--- a/core/src/test/java/org/apache/metamodel/schema/MutableSchemaTest.java
+++ b/core/src/test/java/org/apache/metamodel/schema/MutableSchemaTest.java
@@ -18,9 +18,19 @@
  */
 package org.apache.metamodel.schema;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
-public class MutableSchemaTest extends TestCase {
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Arrays;
+
+import org.apache.metamodel.util.LegacyDeserializationObjectInputStream;
+import org.junit.Test;
+
+public class MutableSchemaTest {
 
     /**
      * Tests that the following (general) rules apply to the object:
@@ -29,6 +39,7 @@ public class MutableSchemaTest extends TestCase {
      * <li>if o1.equals(o2) then this condition must be true: o1.hashCode() ==
      * 02.hashCode()
      */
+    @Test
     public void testEqualsAndHashCode() throws Exception {
         MutableSchema schema1 = new MutableSchema("foo");
         MutableSchema schema2 = new MutableSchema("foo");
@@ -45,6 +56,7 @@ public class MutableSchemaTest extends TestCase {
         assertTrue(schema1.hashCode() == schema2.hashCode());
     }
 
+    @Test
     public void testGetTableByName() throws Exception {
         MutableSchema s = new MutableSchema("foobar");
         s.addTable(new MutableTable("Foo"));
@@ -58,4 +70,39 @@ public class MutableSchemaTest extends TestCase {
         // picking the first alternative that matches case insensitively
         assertEquals("Foo", s.getTableByName("fOO").getName());
     }
+
+    @Test
+    public void testDeserializeOldFormat() throws Exception {
+        final File file = new 
File("src/test/resources/metamodel-4.6.0-mutableschema-etc.ser");
+        assertTrue(file.exists());
+
+        try (final FileInputStream in = new FileInputStream(file)) {
+            final LegacyDeserializationObjectInputStream ois = new 
LegacyDeserializationObjectInputStream(in);
+            final Object obj = ois.readObject();
+            assertTrue(obj instanceof MutableSchema);
+            ois.close();
+
+            final MutableSchema sch = (MutableSchema) obj;
+            assertEquals("schema", sch.getName());
+
+            assertEquals(2, sch.getTableCount());
+
+            final Table table1 = sch.getTable(0);
+            assertTrue(table1 instanceof MutableTable);
+            assertEquals("t1", table1.getName());
+            assertEquals(Arrays.asList("t1_c1", "t1_c2"), 
table1.getColumnNames());
+            assertEquals(1, table1.getRelationshipCount());
+
+            final Table table2 = sch.getTable(1);
+            assertTrue(table2 instanceof MutableTable);
+            assertEquals("t2", table2.getName());
+            assertEquals(Arrays.asList("t2_c1"), table2.getColumnNames());
+            assertEquals(1, table2.getRelationshipCount());
+
+            final Relationship rel1 = 
table1.getRelationships().iterator().next();
+            final Relationship rel2 = 
table2.getRelationships().iterator().next();
+            assertSame(rel1, rel2);
+            assertTrue(rel1 instanceof MutableRelationship);
+        }
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/core/src/test/resources/metamodel-4.6.0-immutableschema-etc.ser
----------------------------------------------------------------------
diff --git a/core/src/test/resources/metamodel-4.6.0-immutableschema-etc.ser 
b/core/src/test/resources/metamodel-4.6.0-immutableschema-etc.ser
new file mode 100644
index 0000000..300bc86
Binary files /dev/null and 
b/core/src/test/resources/metamodel-4.6.0-immutableschema-etc.ser differ

http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/core/src/test/resources/metamodel-4.6.0-mutableschema-etc.ser
----------------------------------------------------------------------
diff --git a/core/src/test/resources/metamodel-4.6.0-mutableschema-etc.ser 
b/core/src/test/resources/metamodel-4.6.0-mutableschema-etc.ser
new file mode 100644
index 0000000..f838a77
Binary files /dev/null and 
b/core/src/test/resources/metamodel-4.6.0-mutableschema-etc.ser differ

http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/csv/src/main/java/org/apache/metamodel/csv/CsvTable.java
----------------------------------------------------------------------
diff --git a/csv/src/main/java/org/apache/metamodel/csv/CsvTable.java 
b/csv/src/main/java/org/apache/metamodel/csv/CsvTable.java
index 41b7593..5e0081c 100644
--- a/csv/src/main/java/org/apache/metamodel/csv/CsvTable.java
+++ b/csv/src/main/java/org/apache/metamodel/csv/CsvTable.java
@@ -19,7 +19,14 @@
 package org.apache.metamodel.csv;
 
 import java.io.IOException;
-import java.util.*;
+import java.io.ObjectInputStream;
+import java.io.ObjectInputStream.GetField;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
 
 import org.apache.metamodel.schema.AbstractTable;
 import org.apache.metamodel.schema.Column;
@@ -32,6 +39,7 @@ import 
org.apache.metamodel.schema.naming.ColumnNamingContextImpl;
 import org.apache.metamodel.schema.naming.ColumnNamingSession;
 import org.apache.metamodel.schema.naming.ColumnNamingStrategy;
 import org.apache.metamodel.util.FileHelper;
+import org.apache.metamodel.util.LegacyDeserializationObjectInputStream;
 
 import com.opencsv.CSVReader;
 
@@ -158,4 +166,17 @@ final class CsvTable extends AbstractTable {
     public String getQuote() {
         return null;
     }
+
+    private void readObject(ObjectInputStream stream) throws IOException, 
ClassNotFoundException {
+        final GetField getFields = stream.readFields();
+        Object columns = getFields.get("_columns", null);
+        if (columns instanceof Column[]) {
+            columns = Arrays.<Column> asList((Column[]) columns);
+        }
+        final Object schema = getFields.get("_schema", null);
+        final Object tableName = getFields.get("_tableName", null);
+        LegacyDeserializationObjectInputStream.setField(CsvTable.class, this, 
"_columns", columns);
+        LegacyDeserializationObjectInputStream.setField(CsvTable.class, this, 
"_schema", schema);
+        LegacyDeserializationObjectInputStream.setField(CsvTable.class, this, 
"_tableName", tableName);
+    }
 }

http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/csv/src/test/java/org/apache/metamodel/csv/CsvTableTest.java
----------------------------------------------------------------------
diff --git a/csv/src/test/java/org/apache/metamodel/csv/CsvTableTest.java 
b/csv/src/test/java/org/apache/metamodel/csv/CsvTableTest.java
new file mode 100644
index 0000000..c12dc80
--- /dev/null
+++ b/csv/src/test/java/org/apache/metamodel/csv/CsvTableTest.java
@@ -0,0 +1,78 @@
+/**
+ * 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.metamodel.csv;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.metamodel.DataContext;
+import org.apache.metamodel.schema.Schema;
+import org.apache.metamodel.schema.Table;
+import org.apache.metamodel.util.LegacyDeserializationObjectInputStream;
+import org.junit.Test;
+
+public class CsvTableTest {
+
+    @Test
+    public void testDeserializeOldTable() throws Exception {
+        final File file = new 
File("src/test/resources/MetaModel-4.6.0-CsvTable.ser");
+        try (LegacyDeserializationObjectInputStream in =
+                new LegacyDeserializationObjectInputStream(new 
FileInputStream(file))) {
+            final Object object = in.readObject();
+
+            assertPeopleCsv(object);
+        }
+    }
+
+    @Test
+    public void testSerializeAndDeserializeCurrentVersion() throws Exception {
+        final DataContext dc = new CsvDataContext(new 
File("src/test/resources/csv_people.csv"));
+        final Table table1 = dc.getDefaultSchema().getTables().get(0);
+        assertPeopleCsv(table1);
+
+        final byte[] bytes = SerializationUtils.serialize(table1);
+
+        try (LegacyDeserializationObjectInputStream in =
+                new LegacyDeserializationObjectInputStream(new 
ByteArrayInputStream(bytes))) {
+            final Object object = in.readObject();
+
+            assertPeopleCsv(object);
+        }
+    }
+
+    private void assertPeopleCsv(Object object) {
+        assertTrue(object instanceof CsvTable);
+
+        final Table table = (Table) object;
+
+        assertEquals("csv_people.csv", table.getName());
+
+        final Schema schema = table.getSchema();
+        assertEquals("resources", schema.getName());
+        assertEquals(1, schema.getTables().size());
+        assertEquals(table, schema.getTable(0));
+
+        assertEquals("[id, name, gender, age]", 
table.getColumnNames().toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/metamodel/blob/583e32ae/csv/src/test/resources/MetaModel-4.6.0-CsvTable.ser
----------------------------------------------------------------------
diff --git a/csv/src/test/resources/MetaModel-4.6.0-CsvTable.ser 
b/csv/src/test/resources/MetaModel-4.6.0-CsvTable.ser
new file mode 100644
index 0000000..8a2b112
Binary files /dev/null and 
b/csv/src/test/resources/MetaModel-4.6.0-CsvTable.ser differ

Reply via email to