@Override public <T> DatumReader<T> create(TypeToken<T> type, Schema schema) { return new ReflectionDatumReader<>(schema, type); } }
@Override protected Object readMap(Decoder decoder, Schema sourceSchema, Schema targetSchema, TypeToken<?> targetTypeToken) throws IOException { check(Map.class.isAssignableFrom(targetTypeToken.getRawType()), "Only map type is supported for map data."); Type type = targetTypeToken.getType(); Preconditions.checkArgument(type instanceof ParameterizedType, "Only parameterized map is supported."); // suppressing warning because we know type is not null @SuppressWarnings("ConstantConditions") Type[] typeArgs = ((ParameterizedType) type).getActualTypeArguments(); int len = decoder.readInt(); // unchecked cast is ok, we're assuming the type token is correct @SuppressWarnings("unchecked") Map<Object, Object> map = (Map<Object, Object>) create(targetTypeToken); while (len != 0) { for (int i = 0; i < len; i++) { Map.Entry<Schema, Schema> sourceEntry = sourceSchema.getMapSchema(); Map.Entry<Schema, Schema> targetEntry = targetSchema.getMapSchema(); map.put(read(decoder, sourceEntry.getKey(), targetEntry.getKey(), TypeToken.of(typeArgs[0])), read(decoder, sourceEntry.getValue(), targetEntry.getValue(), TypeToken.of(typeArgs[1]))); } len = decoder.readInt(); } return map; }
@Override protected Object readRecord(Decoder decoder, Schema sourceSchema, Schema targetSchema, TypeToken<?> targetTypeToken) throws IOException { try { Object record = create(targetTypeToken); for (Schema.Field sourceField : sourceSchema.getFields()) { Schema.Field targetField = targetSchema.getField(sourceField.getName()); if (targetField == null) { skip(decoder, sourceField.getSchema()); continue; } FieldAccessor fieldAccessor = getFieldAccessor(targetTypeToken, sourceField.getName()); fieldAccessor.set(record, read(decoder, sourceField.getSchema(), targetField.getSchema(), TypeToken.of(fieldAccessor.getType()))); } return record; } catch (Exception e) { throw propagate(e); } }
@Test public void testMap() throws IOException, UnsupportedTypeException { TypeToken<Map<String, List<String>>> type = new TypeToken<Map<String, List<String>>>() { }; PipedOutputStream os = new PipedOutputStream(); PipedInputStream is = new PipedInputStream(os); DatumWriter<Map<String, List<String>>> writer = getWriter(type); ImmutableMap<String, List<String>> map = ImmutableMap.<String, List<String>>of("k1", Lists.newArrayList("v1"), "k2", Lists.newArrayList("v2", null)); writer.encode(map, new BinaryEncoder(os)); ReflectionDatumReader<Map<String, List<String>>> reader = new ReflectionDatumReader<>(getSchema(type), type); Assert.assertEquals(map, reader.read(new BinaryDecoder(is), getSchema(type))); }
@Nullable @Override public T apply(ByteBuffer input) { byteBufferInput.reset(input); try { final Schema sourceSchema = schemaCache.get(input); Preconditions.checkNotNull(sourceSchema, "Fail to find source schema."); return datumReader.read(decoder, sourceSchema); } catch (IOException e) { throw Throwables.propagate(e); } }
break; case ARRAY: skipArray(decoder, schema.getComponentSchema()); break; case MAP: skipMap(decoder, schema.getMapSchema()); break; case RECORD: skipRecord(decoder, schema); break; case UNION: skip(decoder, schema.getUnionSchema(decoder.readInt())); break;
@Override protected Object readEnum(Decoder decoder, Schema sourceSchema, Schema targetSchema, TypeToken<?> targetTypeToken) throws IOException { String enumValue = sourceSchema.getEnumValue(decoder.readInt()); check(targetSchema.getEnumValues().contains(enumValue), "Enum value '%s' missing in target.", enumValue); try { return targetTypeToken.getRawType().getMethod("valueOf", String.class).invoke(null, enumValue); } catch (Exception e) { throw new IOException(e); } }
@Test public void testURI() throws IOException, UnsupportedTypeException { TypeToken<List<URI>> type = new TypeToken<List<URI>>() { }; PipedOutputStream os = new PipedOutputStream(); PipedInputStream is = new PipedInputStream(os); DatumWriter<List<URI>> writer = getWriter(type); List<URI> writeValue = ImmutableList.of(URI.create("http://www.abc.com")); writer.encode(writeValue, new BinaryEncoder(os)); ReflectionDatumReader<List<URI>> reader = new ReflectionDatumReader<>(getSchema(type), type); Assert.assertEquals(writeValue, reader.read(new BinaryDecoder(is), getSchema(type))); }
private T decode(byte[] bytes) { if (bytes == null) { return null; } // decode T using schema ByteArrayInputStream bis = new ByteArrayInputStream(bytes); BinaryDecoder decoder = new BinaryDecoder(bis); try { return getReflectionDatumReader().read(decoder, this.schema); } catch (IOException e) { // SHOULD NEVER happen throw new DataSetException("Failed to decode read object: " + e.getMessage(), e); } }
break; case ARRAY: skipArray(decoder, schema.getComponentSchema()); break; case MAP: skipMap(decoder, schema.getMapSchema()); break; case RECORD: skipRecord(decoder, schema); break; case UNION: skip(decoder, schema.getUnionSchema(decoder.readInt())); break;
@Override protected Object readEnum(Decoder decoder, Schema sourceSchema, Schema targetSchema, TypeToken<?> targetTypeToken) throws IOException { String enumValue = sourceSchema.getEnumValue(decoder.readInt()); check(targetSchema.getEnumValues().contains(enumValue), "Enum value '%s' missing in target.", enumValue); try { return targetTypeToken.getRawType().getMethod("valueOf", String.class).invoke(null, enumValue); } catch (Exception e) { throw new IOException(e); } }
@Test public void testList() throws IOException, UnsupportedTypeException { TypeToken<List<Long>> type = new TypeToken<List<Long>>() { }; PipedOutputStream os = new PipedOutputStream(); PipedInputStream is = new PipedInputStream(os); List<Long> writeValue = ImmutableList.of(1L, 10L, 100L, 1000L); DatumWriter<List<Long>> writer = getWriter(type); writer.encode(writeValue, new BinaryEncoder(os)); ReflectionDatumReader<List<Long>> reader = new ReflectionDatumReader<>(getSchema(type), type); List<Long> value = reader.read(new BinaryDecoder(is), getSchema(type)); Assert.assertEquals(writeValue, value); }
@Override protected Object readMap(Decoder decoder, Schema sourceSchema, Schema targetSchema, TypeToken<?> targetTypeToken) throws IOException { check(Map.class.isAssignableFrom(targetTypeToken.getRawType()), "Only map type is supported for map data."); Type type = targetTypeToken.getType(); Preconditions.checkArgument(type instanceof ParameterizedType, "Only parameterized map is supported."); // suppressing warning because we know type is not null @SuppressWarnings("ConstantConditions") Type[] typeArgs = ((ParameterizedType) type).getActualTypeArguments(); int len = decoder.readInt(); // unchecked cast is ok, we're assuming the type token is correct @SuppressWarnings("unchecked") Map<Object, Object> map = (Map<Object, Object>) create(targetTypeToken); while (len != 0) { for (int i = 0; i < len; i++) { Map.Entry<Schema, Schema> sourceEntry = sourceSchema.getMapSchema(); Map.Entry<Schema, Schema> targetEntry = targetSchema.getMapSchema(); map.put(read(decoder, sourceEntry.getKey(), targetEntry.getKey(), TypeToken.of(typeArgs[0])), read(decoder, sourceEntry.getValue(), targetEntry.getValue(), TypeToken.of(typeArgs[1]))); } len = decoder.readInt(); } return map; }
@Override protected Object readRecord(Decoder decoder, Schema sourceSchema, Schema targetSchema, TypeToken<?> targetTypeToken) throws IOException { try { Object record = create(targetTypeToken); for (Schema.Field sourceField : sourceSchema.getFields()) { Schema.Field targetField = targetSchema.getField(sourceField.getName()); if (targetField == null) { skip(decoder, sourceField.getSchema()); continue; } FieldAccessor fieldAccessor = getFieldAccessor(targetTypeToken, sourceField.getName()); fieldAccessor.set(record, read(decoder, sourceField.getSchema(), targetField.getSchema(), TypeToken.of(fieldAccessor.getType()))); } return record; } catch (Exception e) { throw propagate(e); } }
@Override public <T> DatumReader<T> create(TypeToken<T> type, Schema schema) { return new ReflectionDatumReader<>(schema, type); } }
private T decode(byte[] bytes) { if (bytes == null) { return null; } // decode T using schema ByteArrayInputStream bis = new ByteArrayInputStream(bytes); BinaryDecoder decoder = new BinaryDecoder(bis); try { return getReflectionDatumReader().read(decoder, this.schema); } catch (IOException e) { // SHOULD NEVER happen throw new DataSetException("Failed to decode read object: " + e.getMessage(), e); } }
private void skipArray(Decoder decoder, Schema componentSchema) throws IOException { int len = decoder.readInt(); while (len != 0) { skip(decoder, componentSchema); len = decoder.readInt(); } }
@Test public void testUUID() throws UnsupportedTypeException, IOException { TypeToken<UUID> type = new TypeToken<UUID>() { }; PipedOutputStream os = new PipedOutputStream(); PipedInputStream is = new PipedInputStream(os); DatumWriter<UUID> writer = getWriter(type); UUID uuid = UUID.randomUUID(); writer.encode(uuid, new BinaryEncoder(os)); ReflectionDatumReader<UUID> reader = new ReflectionDatumReader<>(getSchema(type), type); UUID value = reader.read(new BinaryDecoder(is), getSchema(type)); Assert.assertEquals(uuid, value); }