Skip to content

Commit

Permalink
Support single values in maps (not just proxied interfaces)
Browse files Browse the repository at this point in the history
  • Loading branch information
elandau committed Aug 16, 2016
1 parent 11c8e94 commit e5e5f65
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ <T> T newProxy(final Class<T> type, final String initialPrefix, boolean immutabl
invokers.put(m, createMapProperty(propName, (ParameterizedType)m.getGenericReturnType(), immutable));
} else if (returnType.isInterface()) {
invokers.put(m, createInterfaceProperty(propName, newProxy(returnType, propName, immutable)));
} else if (m.getParameterTypes().length > 0) {
} else if (m.getParameterTypes() != null && m.getParameterTypes().length > 0) {
invokers.put(m, createParameterizedProperty(returnType, propName, nameAnnot.name(), defaultValue));
} else if (immutable) {
invokers.put(m, createImmutablePropertyWithDefault(m.getReturnType(), propName, defaultValue));
Expand Down Expand Up @@ -233,18 +233,30 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
@SuppressWarnings("unchecked")
private <T> MethodInvoker<T> createMapProperty(final String propName, final ParameterizedType type, final boolean immutable) {
final Class<?> valueType = (Class<?>)type.getActualTypeArguments()[1];
Map<String, Object> map = new ReadOnlyMap<String, Object>() {
Map<String, Object> lookup = new ConcurrentHashMap<String, Object>();
@Override
public Object get(final Object key) {
return lookup.computeIfAbsent((String) key, new Function<String, Object>() {
@Override
public Object apply(String key) {
return newProxy(valueType, propName + "." + key, immutable);
}
});
}
};
Map<String, Object> map;
// This is a map for String -> Interface so create a proxy for any value
if (valueType.isInterface()) {
map = new ReadOnlyMap<String, Object>() {
Map<String, Object> lookup = new ConcurrentHashMap<String, Object>();
@Override
public Object get(final Object key) {
return lookup.computeIfAbsent((String) key, new Function<String, Object>() {
@Override
public Object apply(String key) {
return newProxy(valueType, propName + "." + key, immutable);
}
});
}
};
} else {
// This is a map of String -> DecodableType (i.e. String, Long, etc...)
map = new ReadOnlyMap<String, Object>() {
@Override
public Object get(final Object key) {
return config.get(valueType, propName + "." + key);
}
};
}

return (MethodInvoker<T>) createInterfaceProperty(propName, map);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,29 @@ public void testWithMap() {
config.setProperty("children.2.str", "value3");
Assert.assertEquals("value3", sub2.str());
}

public static interface ConfigWithLongMap {
Map<String, Long> getChildren();
}

@Test
public void testWithLongMap() {
SettableConfig config = new DefaultSettableConfig();
config.setProperty("children.1", "123");
config.setProperty("children.2", "456");

PropertyFactory factory = DefaultPropertyFactory.from(config);
ConfigProxyFactory proxy = new ConfigProxyFactory(config, config.getDecoder(), factory);
ConfigWithLongMap withArgs = proxy.newProxy(ConfigWithLongMap.class);

long sub1 = withArgs.getChildren().get("1");
long sub2 = withArgs.getChildren().get("2");

Assert.assertEquals(123, sub1);
Assert.assertEquals(456, sub2);

config.setProperty("children.2", "789");
sub2 = withArgs.getChildren().get("2");
Assert.assertEquals(789, sub2);
}
}

0 comments on commit e5e5f65

Please sign in to comment.