SchemaBinder { public Schema bind(Schema dst, Function<GroupDef, Direction> dirFn) throws IncompatibleSchemaException { Map<String, GroupDef> newGroups = new HashMap<>(); for (GroupDef dstGroup : dst.getGroups()) { Direction dir = dirFn.apply(dstGroup); GroupDef srcGroup = src.getGroup(dstGroup.getName()); GroupBinding groupBinding; ArrayList<FieldDef> newFields = new ArrayList<>(dstGroup.getFields().size()); if (srcGroup == null) { if (src.getGroup(dstGroup.getId()) != null) { throw new IncompatibleSchemaException("Group name mismatch on groups with id "+dstGroup.getId()+"!"); } if (dstGroup.getSuperGroup() != null) { GroupBinding superBinding = newGroups.get(dstGroup.getSuperGroup()).getBinding(); groupBinding = new GroupBinding(superBinding.getFactory(), superBinding.getGroupType() instanceof MissingGroupType ? new MissingGroupType(dstGroup.getId()) : superBinding.getGroupType()); } else { groupBinding = new GroupBinding(Object::new, new MissingGroupType(dstGroup.getId())); } for (FieldDef dstField : dstGroup.getFields()) { newFields.add(new CreateAccessor<>(dstField).bindField(dstField)); } } else { if (srcGroup.getId() != dstGroup.getId()) { throw new IncompatibleSchemaException("Source and destination groups have different ids" + details(dstGroup, dir)); } if (!Objects.equals(srcGroup.getSuperGroup(), dstGroup.getSuperGroup())) { throw new IncompatibleSchemaException("Different group inheritance" + details(dstGroup, dir)); } groupBinding = srcGroup.getBinding(); checkRequiredFields(srcGroup, dstGroup, dir); for (FieldDef dstField : dstGroup.getFields()) { FieldDef srcField = srcGroup.getField(dstField.getName()); if(srcField == null) { try { newFields.add(new CreateAccessor<>(dstField).bindField(dstField)); } catch (SecurityException e) { e.printStackTrace(); } } else { newFields.add(bindField(srcField, dstField, srcGroup, dst, dir)); } } } GroupDef newGroup = new GroupDef(dstGroup.getName(), dstGroup.getId(), dstGroup.getSuperGroup(), newFields, dstGroup.getAnnotations(), groupBinding); newGroups.put(newGroup.getName(), newGroup); } Schema s = new Schema(newGroups.values(), dst.getNamedTypes(), dst.getAnnotations(), src.getBinding(), buildRemovedClassRemap(newGroups, src.getGroups())); return s; } SchemaBinder(Schema src); Schema bind(Schema dst, Function<GroupDef, Direction> dirFn);  }
@Test public void testUpgradeOk() throws IncompatibleSchemaException { Schema schema1 = new SchemaBuilder().addMessages(FooReqV1.class, FooRspV1.class).build(); Schema schema2 = new SchemaBuilder().addMessages(FooReqV2.class, FooRspV2.class).build(); new SchemaBinder(schema1).bind(schema2, SchemaBinderTest::getDirAtClient); }
@Test public void testUpgradeBoundToGroupOk() throws IncompatibleSchemaException { Schema schema1 = new SchemaBuilder().addMessages(FooReqV1.class, FooRspV1.class).build(); Schema schema2 = new SchemaBuilder().addMessages(FooReqV2.class, FooRspV2.class).build(); schema1 = Group.bind(schema1); schema2 = Group.bind(schema2); new SchemaBinder(schema1).bind(schema2, SchemaBinderTest::getDirAtClient); }
@SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testUpgradeEnumWidening() throws IncompatibleSchemaException { Schema original = new SchemaBuilder().addMessages(EnumValueV1.class).build(); Schema upgraded = new SchemaBuilder().addMessages(EnumValueV2.class).build(); Schema inbound = new SchemaBinder(upgraded).bind(original.unbind(), g -> Direction.INBOUND); Schema outbound = new SchemaBinder(original).bind(upgraded.unbind(), g -> Direction.OUTBOUND); assertEquals("Inbound codec has bound enum class", Version2.class, inbound.getGroup("EnumValue").getField("value").getJavaClass()); assertEquals("Outbound codec has bound enum class", Version1.class, outbound.getGroup("EnumValue").getField("value").getJavaClass()); SymbolMapping mapping; mapping = inbound.getGroup("EnumValue").getField("value").getBinding().getSymbolMapping(); assertEquals(Version2.VALUE1, mapping.lookup(0)); assertEquals(Version2.VALUE2, mapping.lookup(1)); assertEquals(Version2.VALUE3, mapping.lookup(2)); assertEquals(Version2.VALUE1, mapping.lookup("VALUE1")); assertEquals(Version2.VALUE2, mapping.lookup("VALUE2")); assertEquals(Version2.VALUE3, mapping.lookup("VALUE3")); mapping = outbound.getGroup("EnumValue").getField("value").getBinding().getSymbolMapping(); assertEquals(Integer.valueOf(2), mapping.getId(Version1.VALUE1)); assertEquals(Integer.valueOf(1), mapping.getId(Version1.VALUE2)); assertEquals(Integer.valueOf(3), mapping.getId(Version1.VALUE3)); assertEquals("VALUE1", mapping.getName(Version1.VALUE1)); assertEquals("VALUE2", mapping.getName(Version1.VALUE2)); assertEquals("VALUE3", mapping.getName(Version1.VALUE3)); }
@SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testUpgradeIntEnumWidening() throws IncompatibleSchemaException { Schema original = new SchemaBuilder().addMessages(IntEnumValueV1.class).build(); Schema upgraded = new SchemaBuilder().addMessages(IntEnumValueV2.class).build(); Schema inbound = new SchemaBinder(upgraded).bind(original.unbind(), g -> Direction.INBOUND); Schema outbound = new SchemaBinder(original).bind(upgraded.unbind(), g -> Direction.OUTBOUND); assertEquals("Inbound codec has bound enum class", int.class, inbound.getGroup("EnumValue").getField("value").getJavaClass()); assertEquals("Outbound codec has bound enum class", int.class, outbound.getGroup("EnumValue").getField("value").getJavaClass()); SymbolMapping mapping; mapping = inbound.getGroup("EnumValue").getField("value").getBinding().getSymbolMapping(); assertEquals(Version2.VALUE1.ordinal(), mapping.lookup(0)); assertEquals(Version2.VALUE2.ordinal(), mapping.lookup(1)); assertEquals(Version2.VALUE3.ordinal(), mapping.lookup(2)); assertEquals(Version2.VALUE1.ordinal(), mapping.lookup("VALUE1")); assertEquals(Version2.VALUE2.ordinal(), mapping.lookup("VALUE2")); assertEquals(Version2.VALUE3.ordinal(), mapping.lookup("VALUE3")); mapping = outbound.getGroup("EnumValue").getField("value").getBinding().getSymbolMapping(); assertEquals(Integer.valueOf(2), mapping.getId(Version1.VALUE1.ordinal())); assertEquals(Integer.valueOf(1), mapping.getId(Version1.VALUE2.ordinal())); assertEquals(Integer.valueOf(3), mapping.getId(Version1.VALUE3.ordinal())); assertEquals("VALUE1", mapping.getName(Version1.VALUE1.ordinal())); assertEquals("VALUE2", mapping.getName(Version1.VALUE2.ordinal())); assertEquals("VALUE3", mapping.getName(Version1.VALUE3.ordinal())); }
@SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testUpgradeIntegerEnumWidening() throws IncompatibleSchemaException { Schema original = new SchemaBuilder().addMessages(IntegerEnumValueV1.class).build(); Schema upgraded = new SchemaBuilder().addMessages(IntegerEnumValueV2.class).build(); Schema inbound = new SchemaBinder(upgraded).bind(original.unbind(), g -> Direction.INBOUND); Schema outbound = new SchemaBinder(original).bind(upgraded.unbind(), g -> Direction.OUTBOUND); assertEquals("Inbound codec has bound enum class", Integer.class, inbound.getGroup("EnumValue").getField("value").getJavaClass()); assertEquals("Outbound codec has bound enum class", Integer.class, outbound.getGroup("EnumValue").getField("value").getJavaClass()); SymbolMapping mapping; mapping = inbound.getGroup("EnumValue").getField("value").getBinding().getSymbolMapping(); assertEquals(Version2.VALUE1.ordinal(), mapping.lookup(0)); assertEquals(Version2.VALUE2.ordinal(), mapping.lookup(1)); assertEquals(Version2.VALUE3.ordinal(), mapping.lookup(2)); assertEquals(Version2.VALUE1.ordinal(), mapping.lookup("VALUE1")); assertEquals(Version2.VALUE2.ordinal(), mapping.lookup("VALUE2")); assertEquals(Version2.VALUE3.ordinal(), mapping.lookup("VALUE3")); mapping = outbound.getGroup("EnumValue").getField("value").getBinding().getSymbolMapping(); assertEquals(Integer.valueOf(2), mapping.getId(Version1.VALUE1.ordinal())); assertEquals(Integer.valueOf(1), mapping.getId(Version1.VALUE2.ordinal())); assertEquals(Integer.valueOf(3), mapping.getId(Version1.VALUE3.ordinal())); assertEquals("VALUE1", mapping.getName(Version1.VALUE1.ordinal())); assertEquals("VALUE2", mapping.getName(Version1.VALUE2.ordinal())); assertEquals("VALUE3", mapping.getName(Version1.VALUE3.ordinal())); }
@Test(expected = IncompatibleSchemaException.class) public void testSameNameDifferentIdOutbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(SameNameDifferentId1.class); Schema schemaWide = new SchemaBuilder().build(SameNameDifferentId2.class); new SchemaBinder(schemaWide).bind(schemaNarrow, g -> Direction.OUTBOUND); }
@Test(expected = IncompatibleSchemaException.class) public void testSameNameDifferentIdInbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(SameNameDifferentId1.class); Schema schemaWide = new SchemaBuilder().build(SameNameDifferentId2.class); new SchemaBinder(schemaWide).bind(schemaNarrow, g -> Direction.INBOUND); }
@Test(expected = IncompatibleSchemaException.class) public void testDifferentNameSameIdInbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(DifferentNameSameId1.class); Schema schemaWide = new SchemaBuilder().build(DifferentNameSameId2.class); new SchemaBinder(schemaWide).bind(schemaNarrow, g -> Direction.INBOUND); }
@Test(expected = IncompatibleSchemaException.class) public void testDifferentNameSameIdOutbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(DifferentNameSameId1.class); Schema schemaWide = new SchemaBuilder().build(DifferentNameSameId2.class); new SchemaBinder(schemaWide).bind(schemaNarrow, g -> Direction.OUTBOUND); }
@Test(expected = IncompatibleSchemaException.class) public void testSeqTypeWideningOutbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(SeqNumberNarrow.class); Schema schemaWide = new SchemaBuilder().build(SeqNumberWide.class); new SchemaBinder(schemaWide).bind(schemaNarrow, g -> Direction.OUTBOUND); }
@Test(expected = IncompatibleSchemaException.class) public void testSeqTypeWideningInbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(SeqNumberNarrow.class); Schema schemaWide = new SchemaBuilder().build(SeqNumberWide.class); new SchemaBinder(schemaWide).bind(schemaNarrow, g -> Direction.INBOUND); }
@Test(expected = IncompatibleSchemaException.class) public void testSeqTypeNarrowingOutbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(SeqNumberNarrow.class); Schema schemaWide = new SchemaBuilder().build(SeqNumberWide.class); new SchemaBinder(schemaNarrow).bind(schemaWide, g -> Direction.OUTBOUND); }
@Test(expected = IncompatibleSchemaException.class) public void testSeqTypeNarrowingInbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(SeqNumberNarrow.class); Schema schemaWide = new SchemaBuilder().build(SeqNumberWide.class); new SchemaBinder(schemaNarrow).bind(schemaWide, g -> Direction.INBOUND); }
@Test(expected = IncompatibleSchemaException.class) public void testEnumSeqNarrowingOutbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(SeqEnumEntNarrow.class); Schema schemaWide = new SchemaBuilder().build(SeqEnumEntWide.class); new SchemaBinder(schemaWide).bind(schemaNarrow, g -> Direction.OUTBOUND); }
@Test(expected = IncompatibleSchemaException.class) public void testEnumSeqNarrowingInbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(SeqEnumEntNarrow.class); Schema schemaWide = new SchemaBuilder().build(SeqEnumEntWide.class); new SchemaBinder(schemaNarrow).bind(schemaWide, g -> Direction.INBOUND); }
@Test public void testEnumSeqWideningOutbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(SeqEnumEntNarrow.class); Schema schemaWide = new SchemaBuilder().build(SeqEnumEntWide.class); new SchemaBinder(schemaNarrow).bind(schemaWide, g -> Direction.OUTBOUND); }
@Test public void testEnumSeqWideningInbound() throws IncompatibleSchemaException { Schema schemaNarrow = new SchemaBuilder().build(SeqEnumEntNarrow.class); Schema schemaWide = new SchemaBuilder().build(SeqEnumEntWide.class); new SchemaBinder(schemaWide).bind(schemaNarrow, g -> Direction.INBOUND); }