/** * given a list of objects returns the objects either in a DataList, or, if they are PathSpecs * (projections), encode them and return a String. */ private static Object coerceList(List<?> values, Class<?> elementClass, ProtocolVersion version) { assert values != null; DataList dataList = new DataList(); for (Object value : values) { if (value != null) { dataList.add(paramToDataObject(value, elementClass, version)); } } return dataList; }
/** * This method trims doc (1st arg) according to projected (2nd arg), which may have been modified * by projection. This method works in-place, meaning that the doc may be mutated. */ private static void trim(DataMap doc, DataMap projected) { DataMap toAddDoc = new DataMap(); Set<String> fields = doc.keySet(); List<String> toRemoveDoc = new ArrayList<String>(fields.size()); for (String f : fields) { Object v = doc.get(f); if (f.equals(PatchConstants.DELETE_COMMAND)) { DataList deletedFields = (DataList) v; DataList filteredDeleteFields = new DataList(); for (Object patchDeleteField : deletedFields) { if (projected.containsKey(patchDeleteField)) { filteredDeleteFields.add(patchDeleteField); } } toRemoveDoc.add(f); if (!filteredDeleteFields.isEmpty()) { toAddDoc.put(PatchConstants.DELETE_COMMAND, filteredDeleteFields); } } else if (f.equals(PatchConstants.SET_COMMAND)) { DataMap setFields = (DataMap) v; Set<String> setFieldNames = setFields.keySet(); List<String> toRemove = new LinkedList<String>(); DataMap filteredSetFields = new DataMap(); for (String setFieldName : setFieldNames) { if (projected.containsKey(setFieldName)) { filteredSetFields.put(setFieldName, projected.get(setFieldName)); } toRemove.add(setFieldName); } for (String fieldToRemove : toRemove) { setFields.remove(fieldToRemove); if (filteredSetFields.containsKey(fieldToRemove)) { setFields.put(fieldToRemove, filteredSetFields.get(fieldToRemove)); } } if (setFields.isEmpty()) { toRemoveDoc.add(f); } } else if (v instanceof DataMap) { if (projected.containsKey(f)) { trim((DataMap) v, (DataMap) projected.get(f)); } else { toRemoveDoc.add(f); } } } // apply changes to doc for (String f : toRemoveDoc) { doc.remove(f); } for (String f : toAddDoc.keySet()) { doc.put(f, toAddDoc.get(f)); } }
@SuppressWarnings("unchecked") public <ArrayTemplate extends AbstractArrayTemplate<E>, E extends Number> void testNumberArray( Class<ArrayTemplate> templateClass, ArrayDataSchema schema, List<E> castTo, List<? extends Number> castFrom) throws InstantiationException, IllegalAccessException { // test insert non-native, converted to element type on set ArrayTemplate array1 = templateClass.newInstance(); array1.addAll((List<E>) castFrom); for (int i = 0; i < castTo.size(); ++i) { assertEquals(castTo.get(i), array1.get(i)); assertEquals(array1.data().get(i), castTo.get(i)); } // test underlying is non-native, convert on get to element type on get. DataList dataList2 = new DataList(castFrom); ArrayTemplate array2 = DataTemplateUtil.wrap(dataList2, schema, templateClass); for (int i = 0; i < castTo.size(); ++i) { assertSame(dataList2.get(i), castFrom.get(i)); assertEquals(castTo.get(i), array2.get(i)); } }
public <ArrayTemplate extends AbstractArrayTemplate<E>, E> void testArray( Class<ArrayTemplate> templateClass, ArrayDataSchema schema, List<E> input, List<E> adds) throws InstantiationException, IllegalAccessException { // out.println("Testing " + templateClass.getName() + " " + schema.toString()); // constructors and addAll ArrayTemplate array1 = templateClass.newInstance(); array1.addAll(input); assertEquals(input, array1); /* Constructor[] constructors = templateClass.getConstructors(); for (Constructor c : constructors) { out.println(c); } */ try { int size = input.size(); // constructor(int capacity) Constructor<ArrayTemplate> capacityConstructor = templateClass.getConstructor(int.class); ArrayTemplate array = capacityConstructor.newInstance(input.size()); assertEquals(array, Collections.emptyList()); array.addAll(input); assertEquals(input, array); array.clear(); assertEquals(size, input.size()); // constructor(Collection<E>) Constructor<ArrayTemplate> collectionConstructor = templateClass.getConstructor(Collection.class); array = collectionConstructor.newInstance(input); assertEquals(input, array); array.clear(); assertEquals(size, input.size()); // constructor(DataList) Constructor<ArrayTemplate> dataListConstructor = templateClass.getConstructor(DataList.class); array = dataListConstructor.newInstance(array1.data()); assertEquals(array1, array); assertEquals(input, array); array.clear(); assertEquals(array1, array); } catch (Exception e) { assertSame(e, null); } // test wrapping array1.clear(); array1.addAll(input); DataList dataList2 = new DataList(); ArrayTemplate array2 = DataTemplateUtil.wrap(dataList2, schema, templateClass); // with schema arg for (E e : input) { if (e instanceof DataTemplate) { dataList2.add(((DataTemplate<?>) e).data()); } else if (e instanceof Enum) { dataList2.add(e.toString()); } else { dataList2.add(e); } } assertEquals(array1, array2); ArrayTemplate array2a = DataTemplateUtil.wrap(dataList2, templateClass); // without schema arg assertEquals(array1, array2a); assertSame(array2.data(), array2a.data()); // schema() ArrayDataSchema schema1 = array1.schema(); assertTrue(schema1 != null); assertEquals(schema1.getType(), DataSchema.Type.ARRAY); assertEquals(schema1, schema); // add(E element), get(int index) ArrayTemplate array3 = templateClass.newInstance(); for (int i = 0; i < adds.size(); ++i) { E value = adds.get(i); assertTrue(array3.add(value)); assertEquals(array3.get(i), value); assertSame(array3.get(i), value); assertTrue(array3.toString().contains(value.toString())); } assertEquals(array3, adds); // add(int index, E element), get(int index) ArrayTemplate array4 = templateClass.newInstance(); for (int i = 0; i < adds.size(); ++i) { E value = adds.get(adds.size() - i - 1); array4.add(0, value); assertEquals(array4.get(0), value); assertSame(array4.get(0), value); } assertEquals(array4, adds); // clear(), isEmpty(), size() assertEquals(array4.size(), adds.size()); assertFalse(array4.isEmpty()); array4.clear(); assertTrue(array4.isEmpty()); assertEquals(array4.size(), 0); // equals() array4.clear(); array4.addAll(input); assertTrue(array4.equals(array4)); assertTrue(array4.equals(input)); assertFalse(array4.equals(null)); assertFalse(array4.equals(adds)); for (int i = 0; i <= input.size(); ++i) { List<E> subList = input.subList(0, i); ArrayTemplate a = templateClass.newInstance(); a.addAll(subList); if (i == input.size()) { assertTrue(array4.equals(subList)); assertTrue(array4.equals(a)); } else { assertFalse(array4.equals(subList)); assertFalse(array4.equals(a)); } } // hashcode() ArrayTemplate array5 = templateClass.newInstance(); array5.addAll(input); assertEquals(array5.hashCode(), array5.data().hashCode()); array5.addAll(adds); assertEquals(array5.hashCode(), array5.data().hashCode()); array5.clear(); int lastHash = 0; for (int i = 0; i < input.size(); ++i) { array5.add(input.get(i)); int newHash = array5.hashCode(); if (i > 0) { assertFalse(newHash == lastHash); } lastHash = newHash; } // indexOf(Object o), lastIndexOf(Object o) ArrayTemplate array6 = templateClass.newInstance(); array6.addAll(adds); for (E e : adds) { assertEquals(array6.indexOf(e), adds.indexOf(e)); assertEquals(array6.lastIndexOf(e), adds.lastIndexOf(e)); } // remove(int index), subList(int fromIndex, int toIndex) ArrayTemplate array7 = templateClass.newInstance(); array7.addAll(input); ArrayTemplate array8 = templateClass.newInstance(); array8.addAll(input); for (int i = 0; i < input.size(); ++i) { array7.remove(0); assertEquals(array7, input.subList(i + 1, input.size())); assertEquals(array7, array8.subList(i + 1, input.size())); } // removeRange(int fromIndex, int toIndex), subList(int fromIndex, int toIndex) for (int from = 0; from < input.size(); ++from) { for (int to = from + 1; to <= input.size(); ++to) { ArrayTemplate arrayRemove = templateClass.newInstance(); arrayRemove.addAll(input); InternalList<E> reference = new InternalList<E>(input); arrayRemove.removeRange(from, to); reference.removeRange(from, to); assertEquals(reference, arrayRemove); } } // set(int index, E element) ArrayTemplate array9 = templateClass.newInstance(); array9.addAll(input); InternalList<E> reference9 = new InternalList<E>(input); for (int i = 0; i < input.size() / 2; ++i) { int k = input.size() - i - 1; E lo = array9.get(i); E hi = array9.get(k); E hiPrev = array9.set(k, lo); E loPrev = array9.set(i, hi); E refHiPrev = reference9.set(k, lo); E refLoPrev = reference9.set(i, hi); assertEquals(hiPrev, refHiPrev); assertEquals(loPrev, refLoPrev); assertEquals(array9.get(i), reference9.get(i)); assertEquals(array9.get(k), reference9.get(k)); } // clone Exception exc = null; ArrayTemplate array10 = templateClass.newInstance(); array10.addAll(input); try { exc = null; @SuppressWarnings("unchecked") ArrayTemplate array10Clone = (ArrayTemplate) array10.clone(); assertEquals(array10Clone, array10); assertTrue(array10Clone != array10); array10Clone.remove(0); assertEquals(array10Clone.size(), array10.size() - 1); assertFalse(array10Clone.equals(array10)); assertTrue(array10.containsAll(array10Clone)); array10.remove(0); assertEquals(array10Clone, array10); } catch (CloneNotSupportedException e) { exc = e; } assert (exc == null); // contains for (int i = 0; i < input.size(); ++i) { ArrayTemplate array = templateClass.newInstance(); E v = input.get(i); array.add(v); for (int k = 0; k < input.size(); ++k) { if (k == i) assertTrue(array.contains(v)); else assertFalse(array.contains(input.get(k))); } } // containsAll ArrayTemplate arrayContainsAll = templateClass.newInstance(); arrayContainsAll.addAll(input); arrayContainsAll.addAll(adds); InternalList<E> referenceContainsAll = new InternalList<E>(input); referenceContainsAll.addAll(adds); for (int from = 0; from < arrayContainsAll.size(); ++from) { for (int to = from + 1; to <= arrayContainsAll.size(); ++to) { boolean testResult = arrayContainsAll.containsAll(referenceContainsAll.subList(from, to)); boolean referenceResult = referenceContainsAll.containsAll(referenceContainsAll.subList(from, to)); assertEquals(testResult, referenceResult); assertTrue(testResult); assertTrue(referenceResult); } boolean testResult2 = arrayContainsAll.subList(from, arrayContainsAll.size()).containsAll(referenceContainsAll); boolean referenceResult2 = referenceContainsAll .subList(from, arrayContainsAll.size()) .containsAll(referenceContainsAll); // out.println("from " + from + " test " + testResult2 + " ref " + referenceResult2); assertEquals(testResult2, referenceResult2); } // removeAll InternalList<E> referenceListRemoveAll = new InternalList<E>(input); referenceListRemoveAll.addAll(adds); for (int from = 0; from < referenceListRemoveAll.size(); ++from) { for (int to = from + 1; to <= referenceListRemoveAll.size(); ++to) { ArrayTemplate arrayRemoveAll = templateClass.newInstance(); arrayRemoveAll.addAll(referenceListRemoveAll); InternalList<E> referenceRemoveAll = new InternalList<E>(referenceListRemoveAll); boolean testResult = arrayRemoveAll.removeAll(referenceListRemoveAll.subList(from, to)); boolean referenceResult = referenceRemoveAll.removeAll(referenceListRemoveAll.subList(from, to)); // out.println("from " + from + " to " + to + " test " + testResult + " " + arrayRemoveAll + // " ref " + referenceResult + " " + referenceRemoveAll); assertEquals(arrayRemoveAll, referenceRemoveAll); assertEquals(testResult, referenceResult); assertTrue(testResult); assertTrue(referenceResult); } } // retainAll InternalList<E> referenceListRetainAll = new InternalList<E>(input); referenceListRetainAll.addAll(adds); for (int from = 0; from < referenceListRetainAll.size(); ++from) { for (int to = from + 1; to <= referenceListRetainAll.size(); ++to) { ArrayTemplate arrayRetainAll = templateClass.newInstance(); arrayRetainAll.addAll(referenceListRetainAll); InternalList<E> referenceRetainAll = new InternalList<E>(referenceListRetainAll); boolean testResult = arrayRetainAll.removeAll(referenceListRetainAll.subList(from, to)); boolean referenceResult = referenceRetainAll.removeAll(referenceListRetainAll.subList(from, to)); // out.println("from " + from + " to " + to + " test " + testResult + " " + arrayRetainAll + // " ref " + referenceResult + " " + referenceRetainAll); assertEquals(arrayRetainAll, referenceRetainAll); assertEquals(testResult, referenceResult); assertTrue(testResult); assertTrue(referenceResult); } } // Iterator ArrayTemplate arrayIt = templateClass.newInstance(); arrayIt.addAll(input); arrayIt.addAll(adds); for (Iterator<E> it = arrayIt.iterator(); it.hasNext(); ) { it.next(); it.remove(); } assertTrue(arrayIt.isEmpty()); // ListIterator hasNext, hasPrevious, next, previous ArrayTemplate arrayListIt = templateClass.newInstance(); arrayListIt.addAll(input); arrayListIt.addAll(adds); for (int i = 0; i <= arrayListIt.size(); ++i) { ListIterator<E> it = arrayListIt.listIterator(i); if (i > 0) { int save = it.nextIndex(); assertTrue(it.hasPrevious()); assertEquals(it.previous(), arrayListIt.get(i - 1)); it.next(); assertEquals(it.nextIndex(), save); } else { assertFalse(it.hasPrevious()); } if (i < arrayListIt.size()) { int save = it.previousIndex(); assertTrue(it.hasNext()); assertEquals(it.next(), arrayListIt.get(i)); it.previous(); assertEquals(it.previousIndex(), save); } else { assertFalse(it.hasNext()); } assertEquals(it.nextIndex(), i); assertEquals(it.previousIndex(), i - 1); } // ListIterator remove for (ListIterator<E> it = arrayListIt.listIterator(); it.hasNext(); ) { it.next(); it.remove(); } assertTrue(arrayListIt.isEmpty()); // ListIterator add arrayListIt.clear(); { ListIterator<E> it = arrayListIt.listIterator(); for (E e : adds) { it.add(e); } } assertEquals(arrayListIt, adds); // ListIterator set for (int i = 0; i < adds.size(); ++i) { ListIterator<E> it = arrayListIt.listIterator(i); it.next(); E value = adds.get(adds.size() - i - 1); it.set(value); } for (int i = 0; i < adds.size(); ++i) { E value = adds.get(adds.size() - i - 1); assertEquals(arrayListIt.get(i), value); } }
@SuppressWarnings("unchecked") public <ArrayTemplate extends AbstractArrayTemplate<E>, E> void testArrayBadInput( Class<ArrayTemplate> templateClass, ArrayDataSchema schema, List<E> good, List<Object> badInput, List<Object> badOutput) throws InstantiationException, IllegalAccessException { Exception exc = null; ArrayTemplate arrayTemplateBad = templateClass.newInstance(); DataList badDataList = new DataList(); ArrayTemplate badWrappedArrayTemplate = DataTemplateUtil.wrap(badDataList, schema, templateClass); List<E> badIn = (List<E>) badInput; // add(E element) for (E o : badIn) { try { exc = null; arrayTemplateBad.add(o); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(o == null || exc instanceof ClassCastException); assertTrue(o != null || exc instanceof NullPointerException); } // add(int index, E element) for (Object o : badIn) { try { exc = null; arrayTemplateBad.add(0, (E) o); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(o == null || exc instanceof ClassCastException); assertTrue(o != null || exc instanceof NullPointerException); } // addAll(Collection<E> c) try { exc = null; arrayTemplateBad.addAll(badIn); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(exc instanceof ClassCastException); // set(int index, E element) arrayTemplateBad.addAll(good); assertTrue(arrayTemplateBad.size() > 1); for (Object o : badIn) { try { exc = null; arrayTemplateBad.set(0, (E) o); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(o == null || exc instanceof ClassCastException); assertTrue(o != null || exc instanceof NullPointerException); } // listIterator add for (Object o : badIn) { try { exc = null; ListIterator<E> it = arrayTemplateBad.listIterator(0); it.add((E) o); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(o == null || exc instanceof ClassCastException); assertTrue(o != null || exc instanceof NullPointerException); } // listIterator set for (Object o : badIn) { try { exc = null; ListIterator<E> it = arrayTemplateBad.listIterator(0); it.next(); it.set((E) o); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(o == null || exc instanceof ClassCastException); assertTrue(o != null || exc instanceof NullPointerException); } badDataList.clear(); badDataList.addAll(badOutput); badWrappedArrayTemplate = DataTemplateUtil.wrap(badDataList, schema, templateClass); // Get returns bad for (int i = 0; i < badWrappedArrayTemplate.size(); ++i) { try { exc = null; badWrappedArrayTemplate.get(i); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(exc instanceof TemplateOutputCastException); } // Set returns bad badDataList.clear(); badDataList.addAll(badOutput); assertEquals(badWrappedArrayTemplate.size(), badOutput.size()); for (int i = 0; i < badWrappedArrayTemplate.size(); ++i) { try { exc = null; badWrappedArrayTemplate.set(i, good.get(0)); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(exc instanceof TemplateOutputCastException); } // Remove returns bad badDataList.clear(); badDataList.addAll(badOutput); assertEquals(badWrappedArrayTemplate.size(), badOutput.size()); for (int i = 0; i < badWrappedArrayTemplate.size(); ++i) { try { exc = null; badWrappedArrayTemplate.remove(0); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(exc instanceof TemplateOutputCastException); } // Iterator returns bad for (Object o : badOutput) { badDataList.clear(); badDataList.add(o); try { exc = null; badWrappedArrayTemplate.iterator().next(); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(exc instanceof TemplateOutputCastException); } // ListIterator returns bad for (Object o : badOutput) { badDataList.clear(); badDataList.add(o); try { exc = null; badWrappedArrayTemplate.listIterator().next(); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(exc instanceof TemplateOutputCastException); } for (Object o : badOutput) { badDataList.clear(); badDataList.add(o); try { exc = null; badWrappedArrayTemplate.listIterator(badWrappedArrayTemplate.size()).previous(); } catch (Exception e) { exc = e; } assertTrue(exc != null); assertTrue(exc instanceof TemplateOutputCastException); } }
private Object translate(Object value, DataSchema dataSchema, Schema avroSchema) { AvroOverride avroOverride = getAvroOverride(dataSchema); if (avroOverride != null) { return avroOverride .getCustomDataTranslator() .dataToAvroGeneric(this, value, dataSchema, avroSchema); } DataSchema dereferencedDataSchema = dataSchema.getDereferencedDataSchema(); DataSchema.Type type = dereferencedDataSchema.getType(); Object result; switch (type) { case NULL: if (value != Data.NULL) { appendMessage("value must be null for null schema"); result = BAD_RESULT; break; } result = null; break; case BOOLEAN: result = ((Boolean) value).booleanValue(); break; case INT: result = ((Number) value).intValue(); break; case LONG: result = ((Number) value).longValue(); break; case FLOAT: result = ((Number) value).floatValue(); break; case DOUBLE: result = ((Number) value).doubleValue(); break; case STRING: result = new Utf8((String) value); break; case BYTES: result = ByteBuffer.wrap(translateBytes(value)); break; case ENUM: String enumValue = value.toString(); EnumDataSchema enumDataSchema = (EnumDataSchema) dereferencedDataSchema; if (enumDataSchema.getSymbols().contains(enumValue) == false) { appendMessage( "enum value %1$s not one of %2$s", enumValue, enumDataSchema.getSymbols()); result = BAD_RESULT; break; } result = _avroAdapter.createEnumSymbol(avroSchema, enumValue); break; case FIXED: byte[] bytes = translateBytes(value); FixedDataSchema fixedDataSchema = (FixedDataSchema) dereferencedDataSchema; if (fixedDataSchema.getSize() != bytes.length) { appendMessage( "ByteString size %1$d != FixedDataSchema size %2$d", bytes.length, fixedDataSchema.getSize()); result = null; break; } GenericData.Fixed fixed = new GenericData.Fixed(avroSchema); fixed.bytes(bytes); result = fixed; break; case MAP: DataMap map = (DataMap) value; DataSchema valueDataSchema = ((MapDataSchema) dereferencedDataSchema).getValues(); Schema valueAvroSchema = avroSchema.getValueType(); Map<String, Object> avroMap = new HashMap<String, Object>(map.size()); for (Map.Entry<String, Object> entry : map.entrySet()) { String key = entry.getKey(); _path.addLast(key); Object entryAvroValue = translate(entry.getValue(), valueDataSchema, valueAvroSchema); _path.removeLast(); avroMap.put(key, entryAvroValue); } result = avroMap; break; case ARRAY: DataList list = (DataList) value; DataSchema elementDataSchema = ((ArrayDataSchema) dereferencedDataSchema).getItems(); Schema elementAvroSchema = avroSchema.getElementType(); GenericData.Array<Object> avroList = new GenericData.Array<Object>(list.size(), avroSchema); for (int i = 0; i < list.size(); i++) { _path.addLast(i); Object entryAvroValue = translate(list.get(i), elementDataSchema, elementAvroSchema); _path.removeLast(); avroList.add(entryAvroValue); } result = avroList; break; case RECORD: map = (DataMap) value; RecordDataSchema recordDataSchema = (RecordDataSchema) dereferencedDataSchema; GenericData.Record avroRecord = new GenericData.Record(avroSchema); for (RecordDataSchema.Field field : recordDataSchema.getFields()) { String fieldName = field.getName(); DataSchema fieldDataSchema = field.getType(); Schema.Field avroField = avroSchema.getField(fieldName); if (avroField == null) { // field present in input but there is no field for it in Avro schema. // TODO: Whether and how to indicate this condition to clients. continue; } _path.addLast(fieldName); Schema fieldAvroSchema = avroField.schema(); Object fieldValue = map.get(fieldName); boolean isOptional = field.getOptional(); if (isOptional) { if (fieldDataSchema.getDereferencedType() != DataSchema.Type.UNION) { if (fieldValue == null) { fieldValue = Data.NULL; fieldDataSchema = DataSchemaConstants.NULL_DATA_SCHEMA; } Map.Entry<String, Schema> fieldAvroEntry = findUnionMember(fieldDataSchema, fieldAvroSchema); if (fieldAvroEntry == null) { _path.removeLast(); continue; } fieldAvroSchema = fieldAvroEntry.getValue(); } else { // already a union if (fieldValue == null) { // field is not present fieldValue = Data.NULL; fieldDataSchema = DataSchemaConstants.NULL_DATA_SCHEMA; } } } else { if (fieldValue == null) { appendMessage("required field is absent"); _path.removeLast(); continue; } } Object fieldAvroValue = translate(fieldValue, fieldDataSchema, fieldAvroSchema); avroRecord.put(fieldName, fieldAvroValue); _path.removeLast(); } result = avroRecord; break; case UNION: UnionDataSchema unionDataSchema = (UnionDataSchema) dereferencedDataSchema; String key; Object memberValue; if (value == Data.NULL) { key = DataSchemaConstants.NULL_TYPE; memberValue = Data.NULL; } else { map = (DataMap) value; Map.Entry<String, Object> entry = map.entrySet().iterator().next(); key = entry.getKey(); memberValue = entry.getValue(); } DataSchema memberDataSchema = unionDataSchema.getType(key); Map.Entry<String, Schema> memberAvroEntry = findUnionMember(memberDataSchema, avroSchema); if (memberAvroEntry == null) { result = BAD_RESULT; break; } Schema memberAvroSchema = memberAvroEntry.getValue(); _path.addLast(memberAvroEntry.getKey()); Object memberAvroValue = translate(memberValue, memberDataSchema, memberAvroSchema); _path.removeLast(); result = memberAvroValue; break; default: appendMessage("schema type unknown %1$s", dereferencedDataSchema.getType()); result = BAD_RESULT; break; } return result; }
private Object translate(Object value, DataSchema dataSchema, Schema avroSchema) { AvroOverride avroOverride = getAvroOverride(dataSchema); if (avroOverride != null) { return avroOverride .getCustomDataTranslator() .avroGenericToData(this, value, avroSchema, dataSchema); } DataSchema dereferencedDataSchema = dataSchema.getDereferencedDataSchema(); DataSchema.Type type = dereferencedDataSchema.getType(); Object result; switch (type) { case NULL: if (value != null) { appendMessage("value must be null for null schema"); result = BAD_RESULT; break; } result = Data.NULL; break; case BOOLEAN: result = ((Boolean) value).booleanValue(); break; case INT: result = ((Number) value).intValue(); break; case LONG: result = ((Number) value).longValue(); break; case FLOAT: result = ((Number) value).floatValue(); break; case DOUBLE: result = ((Number) value).doubleValue(); break; case STRING: result = value.toString(); break; case BYTES: ByteBuffer byteBuffer = (ByteBuffer) value; ByteString byteString = ByteString.copy(byteBuffer); byteBuffer.rewind(); result = byteString; break; case ENUM: String enumValue = value.toString(); EnumDataSchema enumDataSchema = (EnumDataSchema) dereferencedDataSchema; if (enumDataSchema.getSymbols().contains(enumValue) == false) { appendMessage( "enum value %1$s not one of %2$s", enumValue, enumDataSchema.getSymbols()); result = BAD_RESULT; break; } result = enumValue; break; case FIXED: GenericFixed fixed = (GenericFixed) value; byte[] fixedBytes = fixed.bytes(); FixedDataSchema fixedDataSchema = (FixedDataSchema) dereferencedDataSchema; if (fixedDataSchema.getSize() != fixedBytes.length) { appendMessage( "GenericFixed size %1$d != FixedDataSchema size %2$d", fixedBytes.length, fixedDataSchema.getSize()); result = BAD_RESULT; break; } byteString = ByteString.copy(fixedBytes); result = byteString; break; case MAP: @SuppressWarnings("unchecked") Map<?, Object> map = (Map<?, Object>) value; DataSchema valueDataSchema = ((MapDataSchema) dereferencedDataSchema).getValues(); Schema valueAvroSchema = avroSchema.getValueType(); DataMap dataMap = new DataMap(map.size()); for (Map.Entry<?, Object> entry : map.entrySet()) { String key = entry.getKey().toString(); _path.addLast(key); Object entryValue = translate(entry.getValue(), valueDataSchema, valueAvroSchema); _path.removeLast(); dataMap.put(key, entryValue); } result = dataMap; break; case ARRAY: GenericArray<?> list = (GenericArray<?>) value; DataSchema elementDataSchema = ((ArrayDataSchema) dereferencedDataSchema).getItems(); Schema elementAvroSchema = avroSchema.getElementType(); DataList dataList = new DataList(list.size()); for (int i = 0; i < list.size(); i++) { _path.addLast(i); Object entryValue = translate(list.get(i), elementDataSchema, elementAvroSchema); _path.removeLast(); dataList.add(entryValue); } result = dataList; break; case RECORD: GenericRecord record = (GenericRecord) value; RecordDataSchema recordDataSchema = (RecordDataSchema) dereferencedDataSchema; dataMap = new DataMap(avroSchema.getFields().size()); for (RecordDataSchema.Field field : recordDataSchema.getFields()) { String fieldName = field.getName(); Object fieldValue = record.get(fieldName); // fieldValue could be null if the Avro schema does not contain the named field or // the field is present with a null value. In either case we do not add a value // to the translated DataMap. We do not consider optional/required/default here // either (i.e. it is not an error if a required field is missing); the user can // later call ValidateDataAgainstSchema with various // settings for RequiredMode to obtain the desired behaviour. if (fieldValue == null) { continue; } boolean isOptional = field.getOptional(); DataSchema fieldDataSchema = field.getType(); Schema fieldAvroSchema = avroSchema.getField(fieldName).schema(); if (isOptional && (fieldDataSchema.getDereferencedType() != DataSchema.Type.UNION)) { // Avro schema should be union with 2 types: null and the field's type. Map.Entry<String, Schema> fieldAvroEntry = findUnionMember(fieldDataSchema, fieldAvroSchema); if (fieldAvroEntry == null) { continue; } fieldAvroSchema = fieldAvroEntry.getValue(); } _path.addLast(fieldName); dataMap.put(fieldName, translate(fieldValue, fieldDataSchema, fieldAvroSchema)); _path.removeLast(); } result = dataMap; break; case UNION: UnionDataSchema unionDataSchema = (UnionDataSchema) dereferencedDataSchema; Map.Entry<DataSchema, Schema> memberSchemas = findUnionMemberSchema(value, unionDataSchema, avroSchema); if (memberSchemas == null) { result = BAD_RESULT; break; } if (value == null) { // schema must be "null" schema result = Data.NULL; } else { DataSchema memberDataSchema = memberSchemas.getKey(); Schema memberAvroSchema = memberSchemas.getValue(); String key = memberDataSchema.getUnionMemberKey(); dataMap = new DataMap(1); _path.addLast(key); dataMap.put(key, translate(value, memberDataSchema, memberAvroSchema)); _path.removeLast(); result = dataMap; } break; default: appendMessage("schema type unknown %1$s", dereferencedDataSchema.getType()); result = BAD_RESULT; break; } return result; }
/** * Build a method argument from a request parameter that is an array * * @param context {@link ResourceContext} * @param param {@link Parameter} * @return argument value in the correct type */ private static Object buildArrayArgument( final ResourceContext context, final Parameter<?> param) { final Object convertedValue; if (DataTemplate.class.isAssignableFrom(param.getItemType())) { final DataList itemsList = (DataList) context.getStructuredParameter(param.getName()); convertedValue = Array.newInstance(param.getItemType(), itemsList.size()); int j = 0; for (Object paramData : itemsList) { final DataTemplate<?> itemsElem = DataTemplateUtil.wrap(paramData, param.getItemType().asSubclass(DataTemplate.class)); ValidateDataAgainstSchema.validate( itemsElem.data(), itemsElem.schema(), new ValidationOptions( RequiredMode.CAN_BE_ABSENT_IF_HAS_DEFAULT, CoercionMode.STRING_TO_PRIMITIVE)); Array.set(convertedValue, j++, itemsElem); } } else { final List<String> itemStringValues = context.getParameterValues(param.getName()); ArrayDataSchema parameterSchema = null; if (param.getDataSchema() instanceof ArrayDataSchema) { parameterSchema = (ArrayDataSchema) param.getDataSchema(); } else { throw new RoutingException( "An array schema is expected.", HttpStatus.S_400_BAD_REQUEST.getCode()); } convertedValue = Array.newInstance(param.getItemType(), itemStringValues.size()); int j = 0; for (String itemStringValue : itemStringValues) { if (itemStringValue == null) { throw new RoutingException( "Parameter '" + param.getName() + "' cannot contain null values", HttpStatus.S_400_BAD_REQUEST.getCode()); } try { Array.set( convertedValue, j++, ArgumentUtils.convertSimpleValue( itemStringValue, parameterSchema.getItems(), param.getItemType())); } catch (NumberFormatException e) { Class<?> targetClass = DataSchemaUtil.dataSchemaTypeToPrimitiveDataSchemaClass( parameterSchema.getItems().getDereferencedType()); // thrown from Integer.valueOf or Long.valueOf throw new RoutingException( String.format( "Array parameter '%s' value '%s' must be of type '%s'", param.getName(), itemStringValue, targetClass.getName()), HttpStatus.S_400_BAD_REQUEST.getCode()); } catch (IllegalArgumentException e) { // thrown from Enum.valueOf throw new RoutingException( String.format( "Array parameter '%s' value '%s' is invalid", param.getName(), itemStringValue), HttpStatus.S_400_BAD_REQUEST.getCode()); } catch (TemplateRuntimeException e) { // thrown from DataTemplateUtil.coerceOutput throw new RoutingException( String.format( "Array parameter '%s' value '%s' is invalid. Reason: %s", param.getName(), itemStringValue, e.getMessage()), HttpStatus.S_400_BAD_REQUEST.getCode()); } } } return convertedValue; }