From eb603e80936af64717f8631c6b5a28c60d32002c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20S=C3=B8rensen?= Date: Tue, 29 Aug 2017 21:37:51 -0700 Subject: [PATCH] METAMODEL-1160 and METAMODEL-1163: Fixed --- CHANGES.md | 2 + .../schema/ImmutableRelationship.java | 20 +++++ .../metamodel/schema/MutableRelationship.java | 18 ++++ ...egacyDeserializationObjectInputStream.java | 18 ++++ .../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 .../org/apache/metamodel/csv/CsvTable.java | 23 +++++- .../apache/metamodel/csv/CsvTableTest.java | 78 ++++++++++++++++++ .../resources/MetaModel-4.6.0-CsvTable.ser | Bin 0 -> 1407 bytes 12 files changed, 264 insertions(+), 14 deletions(-) create mode 100644 core/src/test/resources/metamodel-4.6.0-immutableschema-etc.ser create mode 100644 core/src/test/resources/metamodel-4.6.0-mutableschema-etc.ser create mode 100644 csv/src/test/java/org/apache/metamodel/csv/CsvTableTest.java create mode 100644 csv/src/test/resources/MetaModel-4.6.0-CsvTable.ser diff --git a/CHANGES.md b/CHANGES.md index 57cf422dd..a0692ca2d 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 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 7ca8fe9c3..0d4d1df9f 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 List getPrimaryColumns() { public List 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. asList((Column[]) primaryColumns); + foreignColumns = Arrays. asList((Column[]) foreignColumns); + } + LegacyDeserializationObjectInputStream.setField(ImmutableRelationship.class, this, "primaryColumns", + primaryColumns); + LegacyDeserializationObjectInputStream.setField(ImmutableRelationship.class, this, "foreignColumns", + foreignColumns); + } } 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 3ea624c11..47206cd99 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 List 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. asList((Column[]) primaryColumns); + foreignColumns = Arrays. asList((Column[]) foreignColumns); + } + LegacyDeserializationObjectInputStream.setField(MutableRelationship.class, this, "_primaryColumns", + primaryColumns); + LegacyDeserializationObjectInputStream.setField(MutableRelationship.class, this, "_foreignColumns", + foreignColumns); + } } \ No newline at end of file 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 95fad92bd..c39f27a12 100644 --- a/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java +++ b/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java @@ -44,6 +44,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 diff --git a/core/src/test/java/org/apache/metamodel/MetaModelTestCase.java b/core/src/test/java/org/apache/metamodel/MetaModelTestCase.java index 56d57c870..75cc1b573 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 { *
  • Views: The ProjectContributor view
  • * */ - protected Schema getExampleSchema() { + public static Schema getExampleSchema() { MutableSchema schema = new MutableSchema("MetaModelSchema"); MutableTable table1 = new MutableTable(TABLE_CONTRIBUTOR, TableType.TABLE, schema); 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 16c74f9b6..b127f8ed2 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 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 cc313eeb7..f68d13d84 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 { *
  • 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 void testEqualsAndHashCode() throws Exception { 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 void testGetTableByName() throws Exception { // 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 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 0000000000000000000000000000000000000000..300bc86b8e18d3fb130f92511f0e93a44be681a0 GIT binary patch literal 1851 zcma)-J8#oa6vt28q$z2r`annwoe<)s+D(K|rA%!VRTd_oBnZ(C(M@tmUHt0xb#OXV z>H-5R3=Bw>=-7=9!OkZ@>_}`#Ox%YPJ1IEzVCDMWd(Qd)&LihPA?Fjg?~b4zF)V6R#tU*2*1!fG$I*6TzW#a(#k!B&Mr!^=sonFO&++pBS zdFgM|%T>&_pcIpv*P$rM)dIVX$u8tgr;9_}-GzcjOonCf2oDS> z$WslLF$yb*>e3yGdzf(by!0aG1&2ZIV=goLGUo)A#nU!^eam$%jGW2poXAK{6f1?B z)5*qZxRZKVk{IS8wd{rkKM9W|LXu>4pQEK#r{uAR>n%>J@E~r79u_T zqI-VAFnV)eFBT3bNTR4{OW=04s#6GG{U?(>j&Z40=tMyHz)qL@^Dyn^9 z9CbNH&4FL%VK2odqpDo~aeDUqLHHMd;x+XE literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f838a77a89f50c957d962bac88d711a426f3ac77 GIT binary patch literal 1854 zcma)-O=}ZD7{{M%lcqJbuOjr&lZsVowhbbM&_i273Ejq;M2hWUnIvPnb+g&d&c>vN zLP7N4si2?-pt9ZQYGa$ za#3*|$19kkO0|UTxW|?i6kqZwD%dzDRx^jY9|m&Y1~kwNh?ovy$6?smKsBV>$SLbN zN-U?GG$3jUGmpZc-1ezu>xSjgWSzj(pop^tj}la*G9<_+qyf}j3f(d-mh}ja8s~1~ zvxJ}q_g&xlH1_->deH@;G=x2C3)fv{uiX#xH!~U!3am=a^LpPe-ue;$QhKF9)PNqd zShf9%<88urt8%^w8PI2L`c;Z$w^fLGK*6#dwA)6>}m(PY(-C3T)X8myvm5!h?Mco!Uir<1A0x~S3FM& zLv13=+sN}yN-$`8zKcoAJB5ir3c1eXN!Fe<0)wKJ`2dN_Hro5SKfRTFGuLeTTt1u5 zENm0F7Sz8doU1Bfm`x4>{jC@&$FH<+GMs%zI-knU8fN~^a!OqO{!Y}17HSUsJWqS5 zEZPcEQ7gr(>}vpC7C8qUlUNwUEkgbI)TGVwu}Z zbE&MzrA|SkQ*wmxehi6G7GiqqK`2x|X4|Gv*Yb+_)_?Yn&F(cAFz;3gw#tr_j*aO{ zYk|Vab4hNgnpRozoF`b3lR@b;2TglEN&z|8eWDWh>;I5S;N|9xp)->!zXUqY+z5W{zhe%cc literal 0 HcmV?d00001 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 41b7593ab..5e0081c99 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.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 @@ public String getRemarks() { 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. 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); + } } 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 000000000..c12dc80ff --- /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()); + } +} 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 0000000000000000000000000000000000000000..8a2b112c4586752834f7b3a0bb06329ceda44393 GIT binary patch literal 1407 zcma)6OK;Oa5S~0q+EO(|9Juk6cnF&lLW(%FQG_B)Kush>dayRm%DAlU&3bJmJyaa{ z1Kc?v!4XdU4vzc`5a;&7tk=|Oh)jK3d%l_Z9^NlMp%w|a77EuOoH(zk;ZsTca6*~k zM2XRfk|7y03i>IPp|TGR+X-3h2a$wZ`xatNjWtiPW`wPLVs_HHwgne#{YJvg)c_o3 z;;=!AL%^CX)!aV8p0I5lkc60w1g<%d!VBE?Ou(I$TkAQ-&Nz~SIC5!wnDJO-TmQ>A z!)9B5nm%l;J$QLs21FtMDk@bt^I4qktl=kD9$R1EoxCr@dJisUiuGfEOvMNl^nwYU z(a8wbZ7w{Yi1|}GxA5eok`25=X4bxhgslMq_5;u@=yRceI zqjpsW-aU_j8j|Nvdx2*zq3lgKn$l9~FjP8>jN|vK;_Z(Q$G^%@8bK`~ET%JF;#_f4 zfiIk#FWK`s%O_VyC>$fgrO(F))R7i6Z8cfZk4VWEjzVkM=_@&?=Infp;&{n z|fP2VkRs+oZ6 zE2-ffqAo0bhvdGMmwuW5B^%qQt4JsNyfIxKiZPYY6f_EB;n0+SO~NMjwmA(sqw0G7 E15PZv?EnA( literal 0 HcmV?d00001