ProxyInvocationHandler implements InvocationHandler, Serializable { synchronized <T extends PipelineOptions> T as(Class<T> iface) { checkNotNull(iface); checkArgument(iface.isInterface(), "Not an interface: %s", iface); if (!interfaceToProxyCache.containsKey(iface)) { Registration<T> registration = PipelineOptionsFactory.CACHE.get().validateWellFormed(iface, knownInterfaces); List<PropertyDescriptor> propertyDescriptors = registration.getPropertyDescriptors(); Class<T> proxyClass = registration.getProxyClass(); gettersToPropertyNames.putAll(generateGettersToPropertyNames(propertyDescriptors)); settersToPropertyNames.putAll(generateSettersToPropertyNames(propertyDescriptors)); knownInterfaces.add(iface); interfaceToProxyCache.putInstance( iface, InstanceBuilder.ofType(proxyClass) .fromClass(proxyClass) .withArg(InvocationHandler.class, this) .build()); } return interfaceToProxyCache.getInstance(iface); } ProxyInvocationHandler(Map<String, Object> options); private  ProxyInvocationHandler(
      Map<String, BoundValue> options, Map<String, JsonNode> jsonOptions); @Override Object invoke(Object proxy, Method method, Object[] args); String getOptionName(Method method); @Override boolean equals(@Nullable Object obj); @Override int hashCode(); Map<String, Map<String, Object>> outputRuntimeOptions(PipelineOptions options); @Override synchronized String toString();  }
@Test public void testPropertySettingAndGetting() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); Simple proxy = handler.as(Simple.class); proxy.setString("OBJECT"); proxy.setOptionEnabled(true); proxy.setPrimitive(4); assertEquals("OBJECT", proxy.getString()); assertTrue(proxy.isOptionEnabled()); assertEquals(4, proxy.getPrimitive()); }
@Test public void testGettingJLSDefaults() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); JLSDefaults proxy = handler.as(JLSDefaults.class); assertFalse(proxy.getBoolean()); assertEquals('\0', proxy.getChar()); assertEquals((byte) 0, proxy.getByte()); assertEquals((short) 0, proxy.getShort()); assertEquals(0, proxy.getInt()); assertEquals(0L, proxy.getLong()); assertEquals(0f, proxy.getFloat(), 0f); assertEquals(0d, proxy.getDouble(), 0d); assertNull(proxy.getObject()); }
@Test public void testAnnotationDefaults() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); DefaultAnnotations proxy = handler.as(DefaultAnnotations.class); assertTrue(proxy.getBoolean()); assertEquals('a', proxy.getChar()); assertEquals((byte) 4, proxy.getByte()); assertEquals((short) 5, proxy.getShort()); assertEquals(6, proxy.getInt()); assertEquals(7, proxy.getLong()); assertEquals(8f, proxy.getFloat(), 0f); assertEquals(9d, proxy.getDouble(), 0d); assertEquals("testString", proxy.getString()); assertEquals(DefaultAnnotations.class, proxy.getClassOption()); assertEquals(EnumType.MyEnum, proxy.getEnum()); assertEquals("testOptionFactory", proxy.getComplex()); }
@Test public void testEqualsAndHashCode() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); Simple proxy = handler.as(Simple.class); JLSDefaults sameAsProxy = proxy.as(JLSDefaults.class); ProxyInvocationHandler handler2 = new ProxyInvocationHandler(Maps.newHashMap()); Simple proxy2 = handler2.as(Simple.class); JLSDefaults sameAsProxy2 = proxy2.as(JLSDefaults.class); new EqualsTester() .addEqualityGroup(handler, proxy, sameAsProxy) .addEqualityGroup(handler2, proxy2, sameAsProxy2) .testEquals(); }
@Test public void testSubClassStoresSuperInterfaceValues() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); SubClass extended = handler.as(SubClass.class); extended.setString("parentValue"); assertEquals("parentValue", extended.getString()); }
@Test public void testUpCastRetainsSuperInterfaceValues() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); SubClass extended = handler.as(SubClass.class); extended.setString("parentValue"); Simple simple = extended.as(Simple.class); assertEquals("parentValue", simple.getString()); }
@Test public void testUpCastRetainsSubClassValues() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); SubClass extended = handler.as(SubClass.class); extended.setExtended("subClassValue"); SubClass extended2 = extended.as(Simple.class).as(SubClass.class); assertEquals("subClassValue", extended2.getExtended()); }
@Test public void testAsSiblingRetainsSuperInterfaceValues() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); SubClass extended = handler.as(SubClass.class); extended.setString("parentValue"); Sibling sibling = extended.as(Sibling.class); assertEquals("parentValue", sibling.getString()); }
@Test public void testMethodConflictProvidesSameValue() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); MethodConflict methodConflict = handler.as(MethodConflict.class); methodConflict.setString("conflictValue"); assertEquals("conflictValue", methodConflict.getString()); assertEquals("conflictValue", methodConflict.as(Simple.class).getString()); }
@Test public void testDeepMethodConflictProvidesSameValue() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); DeepMethodConflict deepMethodConflict = handler.as(DeepMethodConflict.class); deepMethodConflict.setString("conflictValue"); assertEquals("conflictValue", deepMethodConflict.getString()); assertEquals("conflictValue", deepMethodConflict.as(MethodConflict.class).getString()); assertEquals("conflictValue", deepMethodConflict.as(Simple.class).getString()); deepMethodConflict.setPrimitive(5); assertEquals(5, deepMethodConflict.getPrimitive()); assertEquals(5, deepMethodConflict.as(MethodConflict.class).getPrimitive()); assertEquals(5, deepMethodConflict.as(Simple.class).getPrimitive()); }
@Test public void testDisjointSiblingsShareValues() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); SimpleSibling proxy = handler.as(SimpleSibling.class); proxy.setString("siblingValue"); assertEquals("siblingValue", proxy.getString()); assertEquals("siblingValue", proxy.as(Simple.class).getString()); }
@Test public void testSiblingMethodConflict() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); SiblingMethodConflict siblingMethodConflict = handler.as(SiblingMethodConflict.class); siblingMethodConflict.setString("siblingValue"); assertEquals("siblingValue", siblingMethodConflict.getString()); assertEquals("siblingValue", siblingMethodConflict.as(Simple.class).getString()); assertEquals("siblingValue", siblingMethodConflict.as(SimpleSibling.class).getString()); }
@Test public void testPartialMethodConflictProvidesSameValue() throws Exception { ProxyInvocationHandler handler = new ProxyInvocationHandler(Maps.newHashMap()); PartialMethodConflict partialMethodConflict = handler.as(PartialMethodConflict.class); partialMethodConflict.setString("conflictValue"); assertEquals("conflictValue", partialMethodConflict.getString()); assertEquals("conflictValue", partialMethodConflict.as(Simple.class).getString()); partialMethodConflict.setPrimitive(5); assertEquals(5, partialMethodConflict.getPrimitive()); assertEquals(5, partialMethodConflict.as(Simple.class).getPrimitive()); }
@Test public void testJsonConversionForSimpleTypes() throws Exception { SimpleTypes options = PipelineOptionsFactory.as(SimpleTypes.class); options.setString("TestValue"); options.setInteger(5); SimpleTypes options2 = serializeDeserialize(SimpleTypes.class, options); assertEquals(5, options2.getInteger()); assertEquals("TestValue", options2.getString()); }
@Test public void testJsonConversionOfAJsonConvertedType() throws Exception { SimpleTypes options = PipelineOptionsFactory.as(SimpleTypes.class); options.setString("TestValue"); options.setInteger(5); SimpleTypes options2 = serializeDeserialize( SimpleTypes.class, serializeDeserialize(PipelineOptions.class, options)); assertEquals(5, options2.getInteger()); assertEquals("TestValue", options2.getString()); }
@Test public void testJsonConversionForPartiallySerializedValues() throws Exception { SimpleTypes options = PipelineOptionsFactory.as(SimpleTypes.class); options.setInteger(5); SimpleTypes options2 = serializeDeserialize(SimpleTypes.class, options); options2.setString("TestValue"); SimpleTypes options3 = serializeDeserialize(SimpleTypes.class, options2); assertEquals(5, options3.getInteger()); assertEquals("TestValue", options3.getString()); }
@Test public void testJsonConversionForOverriddenSerializedValues() throws Exception { SimpleTypes options = PipelineOptionsFactory.as(SimpleTypes.class); options.setInteger(-5); options.setString("NeedsToBeOverridden"); SimpleTypes options2 = serializeDeserialize(SimpleTypes.class, options); options2.setInteger(5); options2.setString("TestValue"); SimpleTypes options3 = serializeDeserialize(SimpleTypes.class, options2); assertEquals(5, options3.getInteger()); assertEquals("TestValue", options3.getString()); }
@Test public void testJsonConversionForContainerTypes() throws Exception { List<String> list = ImmutableList.of("a", "b", "c"); Map<String, String> map = ImmutableMap.of("d", "x", "e", "y", "f", "z"); Set<String> set = ImmutableSet.of("g", "h", "i"); ContainerTypes options = PipelineOptionsFactory.as(ContainerTypes.class); options.setList(list); options.setMap(map); options.setSet(set); ContainerTypes options2 = serializeDeserialize(ContainerTypes.class, options); assertEquals(list, options2.getList()); assertEquals(map, options2.getMap()); assertEquals(set, options2.getSet()); }
@Test public void testJsonConversionForComplexType() throws Exception { ComplexType complexType = new ComplexType(); complexType.stringField = "stringField"; complexType.intField = 12; complexType.innerType = InnerType.of(12); complexType.genericType = ImmutableList.of(InnerType.of(16234), InnerType.of(24)); ComplexTypes options = PipelineOptionsFactory.as(ComplexTypes.class); options.setComplexType(complexType); ComplexTypes options2 = serializeDeserialize(ComplexTypes.class, options); assertEquals(complexType, options2.getComplexType()); }
@Test public void testJsonConversionOfIgnoredProperty() throws Exception { IgnoredProperty options = PipelineOptionsFactory.as(IgnoredProperty.class); options.setValue("TestValue"); IgnoredProperty options2 = serializeDeserialize(IgnoredProperty.class, options); assertNull(options2.getValue()); }
@Test public void testJsonConversionOfNotSerializableProperty() throws Exception { NotSerializableProperty options = PipelineOptionsFactory.as(NotSerializableProperty.class); options.setValue(new NotSerializable("TestString")); expectedException.expect(JsonMappingException.class); expectedException.expectMessage("Failed to serialize and deserialize property 'value'"); serializeDeserialize(NotSerializableProperty.class, options); }
@Test public void testJsonConversionOfIgnoredNotSerializableProperty() throws Exception { IgnoredNotSerializableProperty options = PipelineOptionsFactory.as(IgnoredNotSerializableProperty.class); options.setValue(new NotSerializable("TestString")); IgnoredNotSerializableProperty options2 = serializeDeserialize(IgnoredNotSerializableProperty.class, options); assertNull(options2.getValue()); }
@Test public void testJsonConversionOfSerializableWithMetadataProperty() throws Exception { SerializableWithMetadataProperty options = PipelineOptionsFactory.as(SerializableWithMetadataProperty.class); options.setValue(new SerializableWithMetadata("TestString")); SerializableWithMetadataProperty options2 = serializeDeserialize(SerializableWithMetadataProperty.class, options); assertEquals("TestString", options2.getValue().getValue()); }
@Test public void testDisplayDataTypes() { Instant now = Instant.now(); TypedOptions options = PipelineOptionsFactory.as(TypedOptions.class); options.setInteger(1234); options.setTimestamp(now); options.setJavaClass(ProxyInvocationHandlerTest.class); options.setObject( new Serializable() { @Override public String toString() { return "foobar"; } }); DisplayData displayData = DisplayData.from(options); assertThat(displayData, hasDisplayItem("integer", 1234)); assertThat(displayData, hasDisplayItem("timestamp", now)); assertThat(displayData, hasDisplayItem("javaClass", ProxyInvocationHandlerTest.class)); assertThat(displayData, hasDisplayItem("object", "foobar")); }
@Test @Category(NeedsRunner.class) public void pipelineOptionsDisplayDataExceptionShouldFail() { Object brokenValueType = new Object() { @JsonValue public int getValue() { return 42; } @Override public String toString() { throw new RuntimeException("oh noes!!"); } }; p.getOptions().as(ObjectPipelineOptions.class).setValue(brokenValueType); p.apply(Create.of(1, 2, 3)); expectedException.expectMessage( ProxyInvocationHandler.PipelineOptionsDisplayData.class.getName()); expectedException.expectMessage("oh noes!!"); p.run(); }
@Test public void testDisplayDataInheritanceNamespace() { ExtendsBaseOptions options = PipelineOptionsFactory.as(ExtendsBaseOptions.class); options.setFoo("bar"); DisplayData displayData = DisplayData.from(options); assertThat( displayData, hasDisplayItem( allOf(hasKey("foo"), hasValue("bar"), hasNamespace(ExtendsBaseOptions.class)))); }
@Test public void testDisplayDataExcludedFromOverriddenBaseClass() { ExtendsBaseOptions options = PipelineOptionsFactory.as(ExtendsBaseOptions.class); options.setFoo("bar"); DisplayData displayData = DisplayData.from(options); assertThat(displayData, not(hasDisplayItem(hasNamespace(BaseOptions.class)))); }
@Test public void testDisplayDataIncludedForDisjointInterfaceHierarchies() { FooOptions fooOptions = PipelineOptionsFactory.as(FooOptions.class); fooOptions.setFoo("foo"); BarOptions barOptions = fooOptions.as(BarOptions.class); barOptions.setBar("bar"); DisplayData data = DisplayData.from(barOptions); assertThat(data, hasDisplayItem(allOf(hasKey("foo"), hasNamespace(FooOptions.class)))); assertThat(data, hasDisplayItem(allOf(hasKey("bar"), hasNamespace(BarOptions.class)))); }
@Test public void testDisplayDataExcludesDefaultValues() { PipelineOptions options = PipelineOptionsFactory.as(HasDefaults.class); DisplayData data = DisplayData.from(options); assertThat(data, not(hasDisplayItem("foo"))); }
@Test public void testDisplayDataExcludesValuesAccessedButNeverSet() { HasDefaults options = PipelineOptionsFactory.as(HasDefaults.class); assertEquals("bar", options.getFoo()); DisplayData data = DisplayData.from(options); assertThat(data, not(hasDisplayItem("foo"))); }
@Test public void testDisplayDataIncludesExplicitlySetDefaults() { HasDefaults options = PipelineOptionsFactory.as(HasDefaults.class); String defaultValue = options.getFoo(); options.setFoo(defaultValue); DisplayData data = DisplayData.from(options); assertThat(data, hasDisplayItem("foo", defaultValue)); }
@Test public void testDisplayDataNullValuesConvertedToEmptyString() throws Exception { FooOptions options = PipelineOptionsFactory.as(FooOptions.class); options.setFoo(null); DisplayData data = DisplayData.from(options); assertThat(data, hasDisplayItem("foo", "")); FooOptions deserializedOptions = serializeDeserialize(FooOptions.class, options); DisplayData deserializedData = DisplayData.from(deserializedOptions); assertThat(deserializedData, hasDisplayItem("foo", "")); }
@Test public void testDisplayDataArrayValue() throws Exception { ArrayOptions options = PipelineOptionsFactory.as(ArrayOptions.class); options.setDeepArray(new String[][] {new String[] {"a", "b"}, new String[] {"c"}}); options.setDeepPrimitiveArray(new int[][] {new int[] {1, 2}, new int[] {3}}); DisplayData data = DisplayData.from(options); assertThat(data, hasDisplayItem("deepArray", "[[a, b], [c]]")); assertThat(data, hasDisplayItem("deepPrimitiveArray", "[[1, 2], [3]]")); ArrayOptions deserializedOptions = serializeDeserialize(ArrayOptions.class, options); DisplayData deserializedData = DisplayData.from(deserializedOptions); assertThat(deserializedData, hasDisplayItem("deepPrimitiveArray", "[[1, 2], [3]]")); }
@Test public void testDisplayDataJsonSerialization() throws IOException { FooOptions options = PipelineOptionsFactory.as(FooOptions.class); options.setFoo("bar"); @SuppressWarnings("unchecked") Map<String, Object> map = MAPPER.readValue(MAPPER.writeValueAsBytes(options), Map.class); assertThat("main pipeline options data keyed as 'options'", map, Matchers.hasKey("options")); assertThat("display data keyed as 'display_data'", map, Matchers.hasKey("display_data")); Map<?, ?> expectedDisplayItem = ImmutableMap.<String, String>builder() .put("namespace", FooOptions.class.getName()) .put("key", "foo") .put("value", "bar") .put("type", "STRING") .build(); @SuppressWarnings("unchecked") List<Map<?, ?>> deserializedDisplayData = (List<Map<?, ?>>) map.get("display_data"); assertThat(deserializedDisplayData, hasItem(expectedDisplayItem)); }
@Test public void testDisplayDataFromDeserializedJson() throws Exception { FooOptions options = PipelineOptionsFactory.as(FooOptions.class); options.setFoo("bar"); DisplayData data = DisplayData.from(options); assertThat(data, hasDisplayItem("foo", "bar")); FooOptions deserializedOptions = serializeDeserialize(FooOptions.class, options); DisplayData dataAfterDeserialization = DisplayData.from(deserializedOptions); assertEquals(data, dataAfterDeserialization); }
@Test public void testDisplayDataDeserializationWithRegistration() throws Exception { PipelineOptionsFactory.register(HasClassOptions.class); HasClassOptions options = PipelineOptionsFactory.as(HasClassOptions.class); options.setClassOption(ProxyInvocationHandlerTest.class); PipelineOptions deserializedOptions = serializeDeserialize(PipelineOptions.class, options); DisplayData displayData = DisplayData.from(deserializedOptions); assertThat(displayData, hasDisplayItem("classOption", ProxyInvocationHandlerTest.class)); }
@Test public void testDisplayDataMissingPipelineOptionsRegistration() throws Exception { HasClassOptions options = PipelineOptionsFactory.as(HasClassOptions.class); options.setClassOption(ProxyInvocationHandlerTest.class); PipelineOptions deserializedOptions = serializeDeserialize(PipelineOptions.class, options); DisplayData displayData = DisplayData.from(deserializedOptions); String expectedJsonValue = MAPPER.writeValueAsString(ProxyInvocationHandlerTest.class); assertThat(displayData, hasDisplayItem("classOption", expectedJsonValue)); }
@Test public void testDisplayDataJsonValueSetAfterDeserialization() throws Exception { FooOptions options = PipelineOptionsFactory.as(FooOptions.class); options.setFoo("bar"); DisplayData data = DisplayData.from(options); assertThat(data, hasDisplayItem("foo", "bar")); FooOptions deserializedOptions = serializeDeserialize(FooOptions.class, options); deserializedOptions.setFoo("baz"); DisplayData dataAfterDeserialization = DisplayData.from(deserializedOptions); assertThat(dataAfterDeserialization, hasDisplayItem("foo", "baz")); }
@Test public void testDisplayDataExcludesJsonIgnoreOptions() { IgnoredProperty options = PipelineOptionsFactory.as(IgnoredProperty.class); options.setValue("foobar"); DisplayData data = DisplayData.from(options); assertThat(data, not(hasDisplayItem("value"))); }