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
