Skip to content

Commit

Permalink
improve coercion of items with generics, esp config keys
Browse files Browse the repository at this point in the history
previously config keys did not properly keep generic information for their contents;
now this information is preserved and the results coerced as per the types.
also enhances the ValueResolver to have clearer semantics when coercing generics in maps/iterables.
  • Loading branch information
ahgittin committed Aug 31, 2018
1 parent 312131c commit 8e48531
Show file tree
Hide file tree
Showing 22 changed files with 311 additions and 125 deletions.
Expand Up @@ -185,7 +185,7 @@ protected void findMethod() {
protected Maybe<?> resolve(Object object, boolean immediate) {
return Tasks.resolving(object, Object.class)
.context(entity().getExecutionContext())
.deep(true)
.deep(true, true)
.immediately(immediate)
.iterator()
.nextOrLast(DslFunctionSource.class);
Expand Down
Expand Up @@ -598,7 +598,7 @@ public Maybe<Object> getImmediately() {

final Function<Object, Object> resolver = new Function<Object, Object>() {
@Override public Object apply(Object value) {
Maybe<Object> result = Tasks.resolving(value, Object.class).context(executionContext).deep(true).immediately(true).getMaybe();
Maybe<Object> result = Tasks.resolving(value, Object.class).context(executionContext).deep(true, true).immediately(true).getMaybe();
if (result.isAbsent()) {
throw new ImmediateValueNotAvailableException();
} else {
Expand Down
Expand Up @@ -677,7 +677,7 @@ protected Maybe<Sensor<?>> getImmediately(Object si, boolean resolved) {
if (!resolved) {
// attempt to resolve, and recurse
final ExecutionContext executionContext = entity().getExecutionContext();
Maybe<Object> resolvedSi = Tasks.resolving(si, Object.class).deep(true).immediately(true).context(executionContext).getMaybe();
Maybe<Object> resolvedSi = Tasks.resolving(si, Object.class).deep(true, true).immediately(true).context(executionContext).getMaybe();
if (resolvedSi.isAbsent()) return Maybe.absent();
return getImmediately(resolvedSi.get(), true);
}
Expand Down Expand Up @@ -780,7 +780,7 @@ private String resolveTemplate(boolean immediately) {
.as(Object.class)
.context(findExecutionContext(this))
.immediately(immediately)
.deep(true)
.deep(true, true)
.description("Resolving substitutions " + substitutions + " for template " + template)
.get();
}
Expand Down
Expand Up @@ -296,7 +296,7 @@ public BasicConfigKey(Builder<T,?> builder) {
}

/** @see ConfigKey#getTypeName() */
@Override public String getTypeName() { return getType().getName(); }
@Override public String getTypeName() { return getTypeToken().toString(); }

/** @see ConfigKey#getType() */
@Override public Class<? super T> getType() { return TypeTokens.getRawType(typeToken, type); }
Expand Down
Expand Up @@ -32,6 +32,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;

/** A config key representing a list of values.
Expand Down Expand Up @@ -63,16 +64,21 @@ public class ListConfigKey<V> extends AbstractCollectionConfigKey<List<V>,List<O
@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(ListConfigKey.class);

@SuppressWarnings("serial")
private static <V> TypeToken<List<V>> typeTokenFor(TypeToken<V> subType) {
return new TypeToken<List<V>>() {}
.where(new TypeParameter<V>() {}, subType);
}

public static class Builder<V> extends BasicConfigKey.Builder<List<V>,Builder<V>> {
protected Class<V> subType;
protected TypeToken<V> subType;

public Builder(TypeToken<V> subType, String name) {
super(new TypeToken<List<V>>() {}, name);
this.subType = (Class<V>) subType.getRawType();
super(typeTokenFor(subType), name);
this.subType = checkNotNull(subType);
}
public Builder(Class<V> subType, String name) {
super(new TypeToken<List<V>>() {}, name);
this.subType = checkNotNull(subType, "subType");
this(TypeToken.of(subType), name);
}
public Builder(ListConfigKey<V> key) {
this(key.getName(), key);
Expand Down Expand Up @@ -110,17 +116,29 @@ public ListConfigKey(Builder<V> builder) {
super(builder, builder.subType);
}

public ListConfigKey(Class<V> subType, String name) {
public ListConfigKey(TypeToken<V> subType, String name) {
this(subType, name, name, null);
}

public ListConfigKey(Class<V> subType, String name, String description) {
public ListConfigKey(TypeToken<V> subType, String name, String description) {
this(subType, name, description, null);
}

@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({ "unchecked" })
public ListConfigKey(TypeToken<V> subType, String name, String description, List<? extends V> defaultValue) {
super(typeTokenFor(subType), subType, name, description, (List<V>)defaultValue);
}

public ListConfigKey(Class<V> subType, String name) {
this(TypeToken.of(subType), name);
}

public ListConfigKey(Class<V> subType, String name, String description) {
this(TypeToken.of(subType), name, description);
}

public ListConfigKey(Class<V> subType, String name, String description, List<? extends V> defaultValue) {
super((Class)List.class, subType, name, description, (List<V>)defaultValue);
this(TypeToken.of(subType), name, description, defaultValue);
}

@Override
Expand All @@ -143,7 +161,7 @@ public static class ListModifications extends StructuredModifications {
/** when passed as a value to a ListConfigKey, causes each of these items to be added.
* if you have just one, no need to wrap in a mod. */
// to prevent confusion (e.g. if a list is passed) we require two objects here.
public static final <T> ListModification<T> add(final T o1, final T o2, final T ...oo) {
public static final <T> ListModification<T> add(final T o1, final T o2, @SuppressWarnings("unchecked") final T ...oo) {
List<T> l = new ArrayList<T>();
l.add(o1); l.add(o2);
for (T o: oo) l.add(o);
Expand Down
Expand Up @@ -18,8 +18,6 @@
*/
package org.apache.brooklyn.core.config;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
Expand All @@ -39,6 +37,7 @@

import com.google.common.base.Supplier;
import com.google.common.collect.Maps;
import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;

/** A config key which represents a map, where contents can be accessed directly via subkeys.
Expand All @@ -65,16 +64,21 @@ public static <V> Builder<V> builder(MapConfigKey<V> key) {
return new Builder<V>(key);
}

@SuppressWarnings("serial")
private static <V> TypeToken<Map<String,V>> typeTokenFor(TypeToken<V> subType) {
return new TypeToken<Map<String,V>>() {}
.where(new TypeParameter<V>() {}, subType);
}

public static class Builder<V> extends BasicConfigKey.Builder<Map<String, V>,Builder<V>> {
protected Class<V> subType;
protected TypeToken<V> subType;

public Builder(TypeToken<V> subType, String name) {
super(new TypeToken<Map<String, V>>() {}, name);
this.subType = (Class<V>) subType.getRawType();
super(typeTokenFor(subType), name);
this.subType = subType;
}
public Builder(Class<V> subType, String name) {
super(new TypeToken<Map<String, V>>() {}, name);
this.subType = checkNotNull(subType, "subType");
this(TypeToken.of(subType), name);
}
public Builder(MapConfigKey<V> key) {
this(key.getName(), key);
Expand Down Expand Up @@ -112,22 +116,33 @@ protected MapConfigKey(Builder<V> builder) {
super(builder, builder.subType);
}

public MapConfigKey(Class<V> subType, String name) {
public MapConfigKey(TypeToken<V> subType, String name) {
this(subType, name, name, null);
}

public MapConfigKey(Class<V> subType, String name, String description) {
public MapConfigKey(TypeToken<V> subType, String name, String description) {
this(subType, name, description, null);
}

// TODO it isn't clear whether defaultValue is an initialValue, or a value to use when map is empty
// probably the latter, currently ... but maybe better to say that map configs are never null,
// and defaultValue is really an initial value?
@SuppressWarnings({ "unchecked", "rawtypes" })
public MapConfigKey(Class<V> subType, String name, String description, Map<String, V> defaultValue) {
super((Class)Map.class, subType, name, description, defaultValue);
public MapConfigKey(TypeToken<V> subType, String name, String description, Map<String, V> defaultValue) {
super(typeTokenFor(subType), subType, name, description, defaultValue);
}

public MapConfigKey(Class<V> subType, String name) {
this(TypeToken.of(subType), name);
}

public MapConfigKey(Class<V> subType, String name, String description) {
this(TypeToken.of(subType), name, description);
}

public MapConfigKey(Class<V> subType, String name, String description, Map<String, V> defaultValue) {
this(TypeToken.of(subType), name, description, defaultValue);
}

@Override
public String toString() {
return String.format("%s[MapConfigKey:%s]", name, getTypeName());
Expand Down
Expand Up @@ -18,8 +18,6 @@
*/
package org.apache.brooklyn.core.config;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
Expand All @@ -31,6 +29,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;

/** A config key representing a set of values.
Expand All @@ -54,16 +53,21 @@ public class SetConfigKey<V> extends AbstractCollectionConfigKey<Set<V>, Set<Obj
@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(SetConfigKey.class);

@SuppressWarnings("serial")
private static <V> TypeToken<Set<V>> typeTokenFor(TypeToken<V> subType) {
return new TypeToken<Set<V>>() {}
.where(new TypeParameter<V>() {}, subType);
}

public static class Builder<V> extends BasicConfigKey.Builder<Set<V>,Builder<V>> {
protected Class<V> subType;
protected TypeToken<V> subType;

public Builder(TypeToken<V> subType, String name) {
super(new TypeToken<Set<V>>() {}, name);
this.subType = (Class<V>) subType.getRawType();
super(typeTokenFor(subType), name);
this.subType = subType;
}
public Builder(Class<V> subType, String name) {
super(new TypeToken<Set<V>>() {}, name);
this.subType = checkNotNull(subType, "subType");
this(TypeToken.of(subType), name);
}
public Builder(SetConfigKey<V> key) {
this(key.getName(), key);
Expand Down Expand Up @@ -101,17 +105,29 @@ public SetConfigKey(Builder<V> builder) {
super(builder, builder.subType);
}

public SetConfigKey(Class<V> subType, String name) {
public SetConfigKey(TypeToken<V> subType, String name) {
this(subType, name, name, null);
}

public SetConfigKey(Class<V> subType, String name, String description) {
public SetConfigKey(TypeToken<V> subType, String name, String description) {
this(subType, name, description, null);
}

@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({ "unchecked" })
public SetConfigKey(TypeToken<V> subType, String name, String description, Set<? extends V> defaultValue) {
super(typeTokenFor(subType), subType, name, description, (Set<V>) defaultValue);
}

public SetConfigKey(Class<V> subType, String name) {
this(TypeToken.of(subType), name, name, null);
}

public SetConfigKey(Class<V> subType, String name, String description) {
this(TypeToken.of(subType), name, description, null);
}

public SetConfigKey(Class<V> subType, String name, String description, Set<? extends V> defaultValue) {
super((Class)Set.class, subType, name, description, (Set) defaultValue);
this(TypeToken.of(subType), name, description, defaultValue);
}

@Override
Expand All @@ -134,7 +150,7 @@ public static class SetModifications extends StructuredModifications {
/** when passed as a value to a SetConfigKey, causes each of these items to be added.
* if you have just one, no need to wrap in a mod. */
// to prevent confusion (e.g. if a set is passed) we require two objects here.
public static final <T> SetModification<T> add(final T o1, final T o2, final T ...oo) {
public static final <T> SetModification<T> add(final T o1, final T o2, @SuppressWarnings("unchecked") final T ...oo) {
Set<T> l = new LinkedHashSet<T>();
l.add(o1); l.add(o2);
for (T o: oo) l.add(o);
Expand Down
Expand Up @@ -24,20 +24,22 @@
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.util.exceptions.Exceptions;

import com.google.common.reflect.TypeToken;

@SuppressWarnings("rawtypes")
public class SubElementConfigKey<T> extends BasicConfigKey<T> {

private static final long serialVersionUID = -1587240876351450665L;

public final ConfigKey parent;

public SubElementConfigKey(ConfigKey parent, Class<T> type, String name) {
public SubElementConfigKey(ConfigKey parent, TypeToken<T> type, String name) {
this(parent, type, name, name, null);
}
public SubElementConfigKey(ConfigKey parent, Class<T> type, String name, String description) {
public SubElementConfigKey(ConfigKey parent, TypeToken<T> type, String name, String description) {
this(parent, type, name, description, null);
}
public SubElementConfigKey(ConfigKey parent, Class<T> type, String name, String description, T defaultValue) {
public SubElementConfigKey(ConfigKey parent, TypeToken<T> type, String name, String description, T defaultValue) {
super(type, name, description, defaultValue);
this.parent = parent;
}
Expand Down
Expand Up @@ -33,17 +33,18 @@
import org.slf4j.LoggerFactory;

import com.google.common.collect.Iterables;
import com.google.common.reflect.TypeToken;

public abstract class AbstractCollectionConfigKey<T, RawT extends Collection<Object>, V> extends AbstractStructuredConfigKey<T, RawT, V> {

private static final long serialVersionUID = 8225955960120637643L;
private static final Logger log = LoggerFactory.getLogger(AbstractCollectionConfigKey.class);

protected AbstractCollectionConfigKey(BasicConfigKey.Builder<T,?> builder, Class<V> subType) {
protected AbstractCollectionConfigKey(BasicConfigKey.Builder<T,?> builder, TypeToken<V> subType) {
super(builder, subType);
}

protected AbstractCollectionConfigKey(Class<T> type, Class<V> subType, String name, String description, T defaultValue) {
protected AbstractCollectionConfigKey(TypeToken<T> type, TypeToken<V> subType, String name, String description, T defaultValue) {
super(type, subType, name, description, defaultValue);
}

Expand Down
Expand Up @@ -29,19 +29,20 @@
import org.apache.brooklyn.util.exceptions.Exceptions;

import com.google.common.collect.Maps;
import com.google.common.reflect.TypeToken;

public abstract class AbstractStructuredConfigKey<T,RawT,V> extends BasicConfigKey<T> implements StructuredConfigKey {

private static final long serialVersionUID = 7806267541029428561L;

protected final Class<V> subType;
protected final TypeToken<V> subType;

protected AbstractStructuredConfigKey(BasicConfigKey.Builder<T,?> builder, Class<V> subType) {
protected AbstractStructuredConfigKey(BasicConfigKey.Builder<T,?> builder, TypeToken<V> subType) {
super(builder);
this.subType = subType;
}

public AbstractStructuredConfigKey(Class<T> type, Class<V> subType, String name, String description, T defaultValue) {
public AbstractStructuredConfigKey(TypeToken<T> type, TypeToken<V> subType, String name, String description, T defaultValue) {
super(type, name, description, defaultValue);
this.subType = subType;
}
Expand Down

0 comments on commit 8e48531

Please sign in to comment.