Java tutorial
/** * 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 ly.stealth.xmlavro; import org.apache.avro.Schema; import org.apache.avro.generic.GenericData; import org.json.JSONException; import org.junit.Test; import org.skyscreamer.jsonassert.JSONAssert; import java.util.Arrays; import java.util.Collections; import java.util.TimeZone; import static junit.framework.Assert.*; public class ConverterTest { @Test public void basic() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='root' type='xs:string'/>" + "</xs:schema>"; Converter.createSchema(xsd); try { // no namespace Converter.createSchema("<schema/>"); fail(); } catch (ConverterException e) { String message = e.getMessage(); assertTrue(message, message.contains("http://www.w3.org/2001/XMLSchema")); assertTrue(message, message.contains("namespace")); } } @Test public void rootIntPrimitive() { rootPrimitiveWithType("xs:int", "-1", Schema.Type.INT, -1); rootPrimitiveWithType("xs:unsignedByte", "1", Schema.Type.INT, 1); rootPrimitiveWithType("xs:unsignedShort", "5", Schema.Type.INT, 5); } @Test public void rootLongPrimitive() { rootPrimitiveWithType("xs:long", "20", Schema.Type.LONG, (long) 20); rootPrimitiveWithType("xs:unsignedInt", "30", Schema.Type.LONG, (long) 30); } @Test public void rootDoublePrimitive() { rootPrimitiveWithType("xs:decimal", "999999999.999999999", Schema.Type.DOUBLE, 999999999.999999999); } @Test public void rootUnsignedLongShouldBeKeptAsAvroString() { rootPrimitiveWithType("xs:unsignedLong", "18446744073709551615", Schema.Type.STRING, "18446744073709551615"); } @Test public void rootDateTimePrimitive() { rootPrimitiveWithType("xs:dateTime", "2014-10-30T14:58:33", Schema.Type.LONG, 1414681113000L); rootPrimitiveWithType("xs:dateTime", "2014-09-10T12:58:33", Schema.Type.LONG, 1410353913000L); DatumBuilder.setDefaultTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); rootPrimitiveWithType("xs:dateTime", "2014-10-30T07:58:33", Schema.Type.LONG, 1414681113000L); rootPrimitiveWithType("xs:dateTime", "2014-09-10T05:58:33", Schema.Type.LONG, 1410353913000L); } public <T> void rootPrimitiveWithType(String xmlType, String xmlValue, Schema.Type avroType, T avroValue) { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='value' type='" + xmlType + "'/>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); assertEquals(avroType, schema.getType()); String xml = "<value>" + xmlValue + "</value>"; assertEquals(avroValue, Converter.createDatum(schema, xml)); } @Test public void severalRoots() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='i' type='xs:int'/>" + " <xs:element name='r'>" + " <xs:complexType>" + " <xs:sequence>" + " <xs:element name='s' type='xs:string'/>" + " </xs:sequence>" + " </xs:complexType>" + " </xs:element>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); assertEquals(Schema.Type.RECORD, schema.getType()); assertTrue("Schema should have a valid name", schema.getName() != null && !schema.getName().isEmpty()); assertEquals(Source.DOCUMENT, schema.getProp(Source.SOURCE)); assertEquals(2, schema.getFields().size()); Schema.Field field0 = schema.getFields().get(0); assertEquals("" + new Source("i"), field0.getProp(Source.SOURCE)); assertEquals(Schema.Type.UNION, field0.schema().getType()); assertEquals(Schema.Type.INT, field0.schema().getTypes().get(1).getType()); assertEquals(Schema.Type.NULL, field0.schema().getTypes().get(0).getType()); Schema.Field field1 = schema.getFields().get(1); assertEquals("" + new Source("r"), field1.getProp(Source.SOURCE)); assertEquals(Schema.Type.UNION, field1.schema().getType()); assertEquals(Schema.Type.RECORD, field1.schema().getTypes().get(1).getType()); assertEquals(Schema.Type.NULL, field1.schema().getTypes().get(0).getType()); String xml = "<i>5</i>"; GenericData.Record record = Converter.createDatum(schema, xml); assertEquals(null, record.get("r")); assertEquals(5, record.get("i")); xml = "<r><s>s</s></r>"; record = Converter.createDatum(schema, xml); GenericData.Record subRecord = (GenericData.Record) record.get("r"); assertEquals("s", subRecord.get("s")); } @Test public void rootRecord() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='root'>" + " <xs:complexType>" + " <xs:sequence>" + " <xs:element name='i' type='xs:int'/>" + " <xs:element name='s' type='xs:string'/>" + " <xs:element name='d' type='xs:double'/>" + " </xs:sequence>" + " </xs:complexType>" + " </xs:element>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); assertEquals(Schema.Type.RECORD, schema.getType()); assertEquals("AnonType_root", schema.getName()); assertEquals(3, schema.getFields().size()); assertEquals(Schema.Type.INT, schema.getField("i").schema().getType()); assertEquals(Schema.Type.STRING, schema.getField("s").schema().getType()); assertEquals(Schema.Type.DOUBLE, schema.getField("d").schema().getType()); String xml = "<root>" + " <i>1</i>" + " <s>s</s>" + " <d>1.0</d>" + "</root>"; GenericData.Record record = Converter.createDatum(schema, xml); assertEquals(1, record.get("i")); assertEquals("s", record.get("s")); assertEquals(1.0, record.get("d")); } @Test public void nestedRecursiveRecords() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:complexType name='type'>" + " <xs:sequence>" + " <xs:element name='node' type='type' minOccurs='0'/>" + " </xs:sequence>" + " </xs:complexType>" + " <xs:element name='root' type='type'/>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); Schema.Field field = schema.getField("node"); Schema subSchema = field.schema(); assertSame(schema, subSchema.getTypes().get(1)); String xml = "<root><node></node></root>"; GenericData.Record record = Converter.createDatum(schema, xml); GenericData.Record child = (GenericData.Record) record.get("node"); assertEquals(record.getSchema(), child.getSchema()); assertNull(child.get("node")); } @Test public void attributes() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='root'>" + " <xs:complexType>" + " <xs:attribute name='required' use='required'/>" + " <xs:attribute name='prohibited' use='prohibited'/>" + " <xs:attribute name='optional' use='optional'/>" + " </xs:complexType>" + " </xs:element>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); Schema.Field required = schema.getField("required"); assertEquals(Schema.Type.STRING, required.schema().getType()); assertNull(schema.getField("prohibited")); Schema.Field optional = schema.getField("optional"); assertEquals(Schema.Type.UNION, optional.schema().getType()); assertEquals(Arrays.asList(Schema.create(Schema.Type.NULL), Schema.create(Schema.Type.STRING)), optional.schema().getTypes()); String xml = "<root required='required' optional='optional'/>"; GenericData.Record record = Converter.createDatum(schema, xml); assertEquals("required", record.get("required")); assertEquals("optional", record.get("optional")); xml = "<root required='required'/>"; record = Converter.createDatum(schema, xml); assertEquals("required", record.get("required")); assertNull(record.get("optional")); } @Test public void uniqueFieldNames() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:complexType name='type'>" + " <xs:sequence>" + " <xs:element name='field' type='xs:string'/>" + " </xs:sequence>" + " <xs:attribute name='field' type='xs:string'/>" + " </xs:complexType>" + " <xs:element name='root' type='type'/>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); assertEquals(2, schema.getFields().size()); Schema.Field field = schema.getField("field"); assertNotNull(field); assertEquals("" + new Source("field", true), field.getProp(Source.SOURCE)); Schema.Field field0 = schema.getField("field0"); assertEquals("" + new Source("field", false), field0.getProp(Source.SOURCE)); String xml = "<root field='value'><field>value0</field></root>"; GenericData.Record record = Converter.createDatum(schema, xml); assertEquals("value", record.get("field")); assertEquals("value0", record.get("field0")); } @Test public void recordWithWildcardField() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:complexType name='type'>" + " <xs:sequence>" + " <xs:element name='field' type='xs:string'/>" + " <xs:any/>" + " </xs:sequence>" + " </xs:complexType>" + " <xs:element name='root' type='type'/>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); assertEquals(2, schema.getFields().size()); Schema.Field wildcardField = schema.getField(Source.WILDCARD); assertEquals(Schema.Type.MAP, wildcardField.schema().getType()); // Two wildcard-matched elements String xml = "<root>" + " <field>field</field>" + " <field0>field0</field0>" + " <field1>field1</field1>" + "</root>"; GenericData.Record record = Converter.createDatum(schema, xml); assertEquals("field", record.get("field")); @SuppressWarnings("unchecked") java.util.Map<String, String> map = (java.util.Map<String, String>) record.get(Source.WILDCARD); assertEquals(2, map.size()); assertEquals("field0", map.get("field0")); assertEquals("field1", map.get("field1")); // No wildcard-matched element xml = "<root><field>field</field></root>"; record = Converter.createDatum(schema, xml); assertEquals("field", record.get("field")); assertEquals(Collections.emptyMap(), record.get(Source.WILDCARD)); } @Test public void severalWildcards() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='root'>" + " <xs:complexType>" + " <xs:sequence>" + " <xs:any/>" + " <xs:any/>" + " </xs:sequence>" + " </xs:complexType>" + " </xs:element>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); assertEquals(1, schema.getFields().size()); Schema.Field field = schema.getField(Source.WILDCARD); assertEquals(null, field.getProp(Source.SOURCE)); } @Test public void optionalElementValues() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='root'>" + " <xs:complexType>" + " <xs:sequence>" + " <xs:element name='required' type='xs:string'/>" + " <xs:element name='optional' type='xs:string' minOccurs='0'/>" + " </xs:sequence>" + " </xs:complexType>" + " </xs:element>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); assertEquals(2, schema.getFields().size()); Schema.Field requiredField = schema.getField("required"); assertEquals(Schema.Type.STRING, requiredField.schema().getType()); Schema.Field optionalField = schema.getField("optional"); Schema optionalSchema = optionalField.schema(); assertEquals(Schema.Type.UNION, optionalSchema.getType()); assertEquals(Arrays.asList(Schema.create(Schema.Type.NULL), Schema.create(Schema.Type.STRING)), optionalSchema.getTypes()); String xml = "<root><required>required</required></root>"; GenericData.Record record = Converter.createDatum(schema, xml); assertEquals("required", record.get("required")); assertNull(record.get("optional")); xml = "<root>" + " <required>required</required>" + " <optional>optional</optional>" + "</root>"; record = Converter.createDatum(schema, xml); assertEquals("optional", record.get("optional")); } @Test public void array() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='root'>" + " <xs:complexType>" + " <xs:sequence>" + " <xs:element name='value' type='xs:string' maxOccurs='unbounded'/>" + " </xs:sequence>" + " </xs:complexType>" + " </xs:element>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); Schema.Field valueField = schema.getField("value"); assertEquals(Schema.Type.ARRAY, valueField.schema().getType()); assertEquals(Schema.Type.STRING, valueField.schema().getElementType().getType()); String xml = "<root>" + " <value>1</value>" + " <value>2</value>" + " <value>3</value>" + "</root>"; GenericData.Record record = Converter.createDatum(schema, xml); assertEquals(Arrays.asList("1", "2", "3"), record.get("value")); } @Test public void choiceElements() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='root'>" + " <xs:complexType>" + " <xs:choice>" + " <xs:element name='s' type='xs:string'/>" + " <xs:element name='i' type='xs:int'/>" + " </xs:choice>" + " </xs:complexType>" + " </xs:element>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); assertEquals(Schema.Type.RECORD, schema.getType()); assertEquals(2, schema.getFields().size()); Schema.Field sField = schema.getField("s"); assertEquals(Schema.Type.UNION, sField.schema().getType()); assertEquals(Arrays.asList(Schema.create(Schema.Type.NULL), Schema.create(Schema.Type.STRING)), sField.schema().getTypes()); Schema.Field iField = schema.getField("i"); assertEquals(Schema.Type.UNION, iField.schema().getType()); assertEquals(Arrays.asList(Schema.create(Schema.Type.NULL), Schema.create(Schema.Type.INT)), iField.schema().getTypes()); String xml = "<root><s>s</s></root>"; GenericData.Record record = Converter.createDatum(schema, xml); assertEquals("s", record.get("s")); xml = "<root><i>1</i></root>"; record = Converter.createDatum(schema, xml); assertEquals(1, record.get("i")); } @Test public void arrayOfUnboundedChoiceElements() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='root'>" + " <xs:complexType>" + " <xs:choice maxOccurs='unbounded'>" + " <xs:element name='s' type='xs:string'/>" + " <xs:element name='i' type='xs:int'/>" + " </xs:choice>" + " </xs:complexType>" + " </xs:element>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); assertEquals(Schema.Type.ARRAY, schema.getType()); final Schema elementType = schema.getElementType(); assertEquals(Schema.Type.RECORD, elementType.getType()); } @Test public void arrayOfChoiceElements() { String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='root'>" + " <xs:complexType>" + " <xs:choice maxOccurs='3'>" + " <xs:element name='s' type='xs:string'/>" + " <xs:element name='i' type='xs:int'/>" + " </xs:choice>" + " </xs:complexType>" + " </xs:element>" + "</xs:schema>"; Schema schema = Converter.createSchema(xsd); assertEquals(Schema.Type.ARRAY, schema.getType()); final Schema elementType = schema.getElementType(); assertEquals(Schema.Type.RECORD, elementType.getType()); assertEquals(2, elementType.getFields().size()); String xml = "<root><s>s</s><i>1</i><i>2</i></root>"; GenericData.Array record = Converter.createDatum(schema, xml); Object firstRecord = record.get(0); assertTrue(firstRecord instanceof GenericData.Record); assertEquals("s", ((GenericData.Record) firstRecord).get("s")); Object secondRecord = record.get(1); assertTrue(secondRecord instanceof GenericData.Record); assertEquals(1, ((GenericData.Record) secondRecord).get("i")); Object thirdRecord = record.get(2); assertTrue(thirdRecord instanceof GenericData.Record); assertEquals(2, ((GenericData.Record) thirdRecord).get("i")); } @Test public void arrayFromComplexTypeChoiceElements() throws JSONException { // Given String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='root'>" + " <xs:complexType>" + " <xs:choice maxOccurs='unbounded'>" + " <xs:element name='s' type='xs:string'/>" + " <xs:element name='i' type='xs:int'/>" + " </xs:choice>" + " </xs:complexType>" + " </xs:element>" + "</xs:schema>"; String xml = "<root>" + "<s>s</s>" + "<i>1</i>" + "<i>2</i>" + "</root>"; // When Schema schema = Converter.createSchema(xsd); Object datum = Converter.createDatum(schema, xml); // Then JSONAssert.assertEquals( "{" + " 'type': 'array'," + " 'items': {" + " 'type': 'record'," + " 'name': 'AnonType_root'," + " 'fields': [" + " {" + " 'name': 's'," + " 'type': ['null', 'string']" + " }," + " {" + " 'name': 'i'," + " 'type': ['null', 'int']" + " }" + " ]" + " }" + "}", schema.toString(), false); JSONAssert.assertEquals("[" + "{'s': 's'}," + "{'i': 1}," + "{'i': 2}" + "]", datum.toString(), false); } @Test public void arrayFromComplexTypeSequenceOfChoiceElements() throws JSONException { // Given String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + " <xs:element name='root'>" + " <xs:complexType>" + " <xs:sequence>" + " <xs:element name='s' type='xs:string'/>" + " <xs:element name='i' type='xs:int'/>" + " <xs:choice maxOccurs='2'>" + " <xs:element name='x' type='xs:string'/>" + " <xs:element name='y' type='xs:int'/>" + " </xs:choice>" + " </xs:sequence>" + " </xs:complexType>" + " </xs:element>" + "</xs:schema>"; String xml = "<root>" + "<s>s</s>" + "<i>1</i>" + "<x>x1</x>" + "<y>2</y>" + "</root>"; // When Schema schema = Converter.createSchema(xsd); Object datum = Converter.createDatum(schema, xml); // Then JSONAssert.assertEquals("{" + " 'type': 'record'," + " 'fields': [" + " {" + " 'name': 's'," + " 'type': 'string'" + " }," + " {" + " 'name': 'i'," + " 'type': 'int'" + " }," + " {" + " 'name': 'type0'," + " 'type': {" + " 'type': 'array'," + " 'items': {" + " 'type': 'record'," + " 'name': 'type1'," + " 'fields': [" + " {" + " 'name': 'x'," + " 'type': ['null','string']" + " }," + " {" + " 'name': 'y'," + " 'type': ['null','int']" + " }" + " ]" + " }" + " }" + " }" + " ]" + "}", schema.toString(), false); JSONAssert.assertEquals("{" + " 's': 's'," + " 'i': 1," + " 'type0': [" + " {'x': 'x1'}," + " {'y': 2}" + " ]" + "}", datum.toString(), false); } @Test public void SchemaBuilder_validName() { SchemaBuilder builder = new SchemaBuilder(); assertNull(builder.validName(null)); assertEquals("", builder.validName("")); assertEquals("a1", builder.validName("$a#1")); assertEquals("a_1", builder.validName("a.1")); assertEquals("a_1", builder.validName("a-1")); // built-in types assertEquals("string0", builder.validName("string")); assertEquals("record1", builder.validName("record")); } }