tidy/enhancements to javalang utils a few more methods which were elsewhere or not present, better methods using Maybe, and callers updated to use them
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/23ab1c50 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/23ab1c50 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/23ab1c50 Branch: refs/heads/master Commit: 23ab1c506bdda9a3ac79199146ea9750d18d9005 Parents: 8644003 Author: Alex Heneveld <[email protected]> Authored: Fri Jun 24 11:13:18 2016 +0100 Committer: Alex Heneveld <[email protected]> Committed: Fri Jun 24 23:02:48 2016 +0100 ---------------------------------------------------------------------- .../creation/BrooklynYamlTypeInstantiator.java | 6 +- .../spi/dsl/methods/BrooklynDslCommon.java | 2 +- .../core/mgmt/entitlement/Entitlements.java | 6 +- .../BasicExternalConfigSupplierRegistry.java | 6 +- .../core/mgmt/internal/LocalUsageManager.java | 4 +- .../core/mgmt/rebind/RebindIteration.java | 3 +- .../core/objs/proxy/InternalFactory.java | 7 +- .../entity/group/DynamicClusterImpl.java | 4 +- .../location/jclouds/JcloudsLocation.java | 15 +- .../java/org/apache/brooklyn/test/Asserts.java | 8 +- .../util/guava/AnyExceptionSupplier.java | 8 +- .../apache/brooklyn/util/javalang/Boxing.java | 29 +++ .../apache/brooklyn/util/javalang/Enums.java | 4 +- .../brooklyn/util/javalang/FieldOrderings.java | 82 +++++++ .../brooklyn/util/javalang/JavaClassNames.java | 18 +- .../util/javalang/ReflectionPredicates.java | 71 ++++++ .../brooklyn/util/javalang/Reflections.java | 239 ++++++++++++++----- .../apache/brooklyn/util/javalang/Threads.java | 1 - .../brooklyn/util/javalang/BoxingTest.java | 5 + .../brooklyn/util/javalang/ReflectionsTest.java | 13 +- 20 files changed, 422 insertions(+), 109 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlTypeInstantiator.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlTypeInstantiator.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlTypeInstantiator.java index 01bfaa2..a8f8c5a 100644 --- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlTypeInstantiator.java +++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlTypeInstantiator.java @@ -129,17 +129,17 @@ public abstract class BrooklynYamlTypeInstantiator { public <T> T newInstance(@Nullable Class<T> supertype) { Class<? extends T> type = getType(supertype); Map<String, ?> cfg = getConfigMap(); - Optional<? extends T> result = Reflections.invokeConstructorWithArgs(type, cfg); + Maybe<? extends T> result = Reflections.invokeConstructorFromArgs(type, cfg); if (result.isPresent()) return result.get(); ConfigBag cfgBag = ConfigBag.newInstance(cfg); - result = Reflections.invokeConstructorWithArgs(type, cfgBag); + result = Reflections.invokeConstructorFromArgs(type, cfgBag); if (result.isPresent()) return result.get(); if (cfg.isEmpty()) { - result = Reflections.invokeConstructorWithArgs(type); + result = Reflections.invokeConstructorFromArgs(type); if (result.isPresent()) return result.get(); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java index 48ea03f..b88829b 100644 --- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java +++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java @@ -359,7 +359,7 @@ public class BrooklynDslCommon { try { bean = (T) TypeCoercions.coerce(fields, type); } catch (ClassCoercionException ex) { - bean = Reflections.invokeConstructorWithArgs(type).get(); + bean = Reflections.invokeConstructorFromArgs(type).get(); BeanUtils.populate(bean, fields); } if (bean instanceof Configurable && config.size() > 0) { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java index 7199267..df3f7a8 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java @@ -21,7 +21,6 @@ package org.apache.brooklyn.core.mgmt.entitlement; import java.util.Arrays; import java.util.List; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.brooklyn.api.entity.Entity; @@ -35,10 +34,10 @@ import org.apache.brooklyn.core.config.ConfigKeys; import org.apache.brooklyn.core.config.Sanitizer; import org.apache.brooklyn.core.internal.BrooklynProperties; import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; -import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.javalang.Reflections; import org.apache.brooklyn.util.text.Strings; import org.slf4j.Logger; @@ -47,7 +46,6 @@ import org.slf4j.LoggerFactory; import com.google.common.annotations.Beta; import com.google.common.base.Joiner; import com.google.common.base.Objects; -import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; @@ -474,7 +472,7 @@ public class Entitlements { private static Object instantiate(Class<?> clazz, List<Object[]> constructorArgOptions) { try { for (Object[] constructorArgOption : constructorArgOptions) { - Optional<?> result = Reflections.invokeConstructorWithArgs(clazz, constructorArgOption); + Maybe<?> result = Reflections.invokeConstructorFromArgs(clazz, constructorArgOption); if (result.isPresent()) return result.get(); } } catch (Exception e) { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BasicExternalConfigSupplierRegistry.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BasicExternalConfigSupplierRegistry.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BasicExternalConfigSupplierRegistry.java index 6b261db..ac67f22 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BasicExternalConfigSupplierRegistry.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BasicExternalConfigSupplierRegistry.java @@ -27,11 +27,11 @@ import org.apache.brooklyn.core.config.ConfigPredicates; import org.apache.brooklyn.core.config.ConfigUtils; import org.apache.brooklyn.core.config.external.ExternalConfigSupplier; import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.javalang.Reflections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Optional; import com.google.common.collect.Maps; /** @@ -102,9 +102,9 @@ public class BasicExternalConfigSupplierRegistry implements ExternalConfigSuppli Map<String, Object> config = ConfigUtils.filterForPrefixAndStrip(externalProviderProperties, key + "."); try { - Optional<ExternalConfigSupplier> configSupplier = Reflections.invokeConstructorWithArgs(classloader, providerClassname, mgmt, name, config); + Maybe<ExternalConfigSupplier> configSupplier = Reflections.invokeConstructorFromArgs(classloader, ExternalConfigSupplier.class, providerClassname, mgmt, name, config); if (!configSupplier.isPresent()) { - configSupplier = Reflections.invokeConstructorWithArgs(classloader, providerClassname, mgmt, name); + configSupplier = Reflections.invokeConstructorFromArgs(classloader, ExternalConfigSupplier.class, providerClassname, mgmt, name); } if (!configSupplier.isPresent()) { throw new IllegalStateException("No matching constructor found in "+providerClassname); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalUsageManager.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalUsageManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalUsageManager.java index 7caf958..50df5c8 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalUsageManager.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalUsageManager.java @@ -50,6 +50,7 @@ import org.apache.brooklyn.core.mgmt.usage.UsageListener; import org.apache.brooklyn.core.mgmt.usage.UsageManager; import org.apache.brooklyn.util.core.flags.TypeCoercions; import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.javalang.Reflections; import org.apache.brooklyn.util.time.Duration; import org.slf4j.Logger; @@ -57,7 +58,6 @@ import org.slf4j.LoggerFactory; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; -import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -142,7 +142,7 @@ public class LocalUsageManager implements UsageManager { @Override public UsageListener apply(String input) { // TODO Want to use classLoader = mgmt.getCatalog().getRootClassLoader(); ClassLoader classLoader = LocalUsageManager.class.getClassLoader(); - Optional<Object> result = Reflections.invokeConstructorWithArgs(classLoader, input); + Maybe<Object> result = Reflections.invokeConstructorFromArgs(classLoader, input); if (result.isPresent()) { return (UsageListener) result.get(); } else { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index 5c77753..6c0bd9d 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -101,7 +101,6 @@ import org.apache.brooklyn.util.time.Time; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableMap; @@ -1118,7 +1117,7 @@ public abstract class RebindIteration { protected <T> T invokeConstructor(Reflections reflections, Class<T> clazz, Object[]... possibleArgs) { for (Object[] args : possibleArgs) { try { - Optional<T> v = Reflections.invokeConstructorWithArgs(clazz, args, true); + Maybe<T> v = Reflections.invokeConstructorFromArgs(clazz, args, true); if (v.isPresent()) { return v.get(); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalFactory.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalFactory.java index f5454fe..0f7e79e 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalFactory.java @@ -28,10 +28,9 @@ import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.javalang.Reflections; -import com.google.common.base.Optional; - /** */ public class InternalFactory { @@ -142,9 +141,9 @@ public class InternalFactory { protected <T> T constructOldStyle(Class<T> clazz, Map<String,?> flags) throws InstantiationException, IllegalAccessException, InvocationTargetException { FactoryConstructionTracker.setConstructing(); - Optional<T> v; + Maybe<T> v; try { - v = Reflections.invokeConstructorWithArgs(clazz, new Object[] {MutableMap.copyOf(flags)}, true); + v = Reflections.invokeConstructorFromArgs(clazz, new Object[] {MutableMap.copyOf(flags)}, true); } finally { FactoryConstructionTracker.reset(); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java index d4d5b1d..0271134 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java +++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java @@ -115,7 +115,7 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus @Override public NodePlacementStrategy apply(final String input) { ClassLoader classLoader = NodePlacementStrategy.class.getClassLoader(); - Optional<NodePlacementStrategy> strategy = Reflections.<NodePlacementStrategy>invokeConstructorWithArgs(classLoader, input); + Maybe<NodePlacementStrategy> strategy = Reflections.invokeConstructorFromArgs(classLoader, NodePlacementStrategy.class, input); if (strategy.isPresent()) { return strategy.get(); } else { @@ -127,7 +127,7 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus @Override public ZoneFailureDetector apply(final String input) { ClassLoader classLoader = ZoneFailureDetector.class.getClassLoader(); - Optional<ZoneFailureDetector> detector = Reflections.<ZoneFailureDetector>invokeConstructorWithArgs(classLoader, input); + Maybe<ZoneFailureDetector> detector = Reflections.invokeConstructorFromArgs(classLoader, ZoneFailureDetector.class, input); if (detector.isPresent()) { return detector.get(); } else { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java index 51e9d6a..58895a8 100644 --- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java +++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java @@ -58,7 +58,6 @@ import org.apache.brooklyn.api.location.NoMachinesAvailableException; import org.apache.brooklyn.api.location.PortRange; import org.apache.brooklyn.api.mgmt.AccessController; import org.apache.brooklyn.api.mgmt.Task; -import org.apache.brooklyn.api.mgmt.TaskAdaptable; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.config.ConfigKey.HasConfigKey; import org.apache.brooklyn.core.BrooklynVersion; @@ -107,8 +106,6 @@ import org.apache.brooklyn.util.core.task.TaskBuilder; import org.apache.brooklyn.util.core.task.TaskInternal; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.core.task.ssh.SshTasks; -import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory; -import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper; import org.apache.brooklyn.util.core.text.TemplateProcessor; import org.apache.brooklyn.util.exceptions.CompoundRuntimeException; import org.apache.brooklyn.util.exceptions.Exceptions; @@ -400,7 +397,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im protected CloudMachineNamer getCloudMachineNamer(ConfigBag config) { String namerClass = config.get(LocationConfigKeys.CLOUD_MACHINE_NAMER_CLASS); if (Strings.isNonBlank(namerClass)) { - Optional<CloudMachineNamer> cloudNamer = Reflections.invokeConstructorWithArgs(getManagementContext().getCatalogClassLoader(), namerClass); + Maybe<CloudMachineNamer> cloudNamer = Reflections.invokeConstructorFromArgs(getManagementContext().getCatalogClassLoader(), CloudMachineNamer.class, namerClass); if (cloudNamer.isPresent()) { return cloudNamer.get(); } else { @@ -425,11 +422,11 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im if (customizer != null) result.add(customizer); if (customizers != null) result.addAll(customizers); if (Strings.isNonBlank(customizerType)) { - Optional<JcloudsLocationCustomizer> customizerByType = Reflections.invokeConstructorWithArgs(catalogClassLoader, customizerType, setup); + Maybe<JcloudsLocationCustomizer> customizerByType = Reflections.invokeConstructorFromArgs(catalogClassLoader, JcloudsLocationCustomizer.class, customizerType, setup); if (customizerByType.isPresent()) { result.add(customizerByType.get()); } else { - customizerByType = Reflections.invokeConstructorWithArgs(catalogClassLoader, customizerType); + customizerByType = Reflections.invokeConstructorFromArgs(catalogClassLoader, JcloudsLocationCustomizer.class, customizerType); if (customizerByType.isPresent()) { result.add(customizerByType.get()); } else { @@ -438,11 +435,11 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im } } if (Strings.isNonBlank(customizersSupplierType)) { - Optional<Supplier<Collection<JcloudsLocationCustomizer>>> supplier = Reflections.invokeConstructorWithArgs(catalogClassLoader, customizersSupplierType, setup); + Maybe<Supplier<Collection<JcloudsLocationCustomizer>>> supplier = Reflections.<Supplier<Collection<JcloudsLocationCustomizer>>>invokeConstructorFromArgsUntyped(catalogClassLoader, customizersSupplierType, setup); if (supplier.isPresent()) { result.addAll(supplier.get().get()); } else { - supplier = Reflections.invokeConstructorWithArgs(catalogClassLoader, customizersSupplierType); + supplier = Reflections.<Supplier<Collection<JcloudsLocationCustomizer>>>invokeConstructorFromArgsUntyped(catalogClassLoader, customizersSupplierType); if (supplier.isPresent()) { result.addAll(supplier.get().get()); } else { @@ -1566,7 +1563,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im Object rawVal = config.getStringKey(JcloudsLocationConfig.IMAGE_CHOOSER.getName()); if (rawVal instanceof String && Strings.isNonBlank((String)rawVal)) { // Configured with a string: it could be a class that we need to instantiate - Optional<?> instance = Reflections.invokeConstructorWithArgs(getManagementContext().getCatalogClassLoader(), (String)rawVal); + Maybe<?> instance = Reflections.invokeConstructorFromArgs(getManagementContext().getCatalogClassLoader(), (String)rawVal); if (!instance.isPresent()) { throw new IllegalStateException("Failed to create ImageChooser "+rawVal+" for location "+this); } else if (!(instance.get() instanceof Function)) { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java b/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java index aa74d1b..a544f01 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java +++ b/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java @@ -1161,8 +1161,12 @@ public class Asserts { /** Throws a {@link ShouldHaveFailedPreviouslyAssertionError} exception, * to more easily distinguish this failure from other fails. * In particular, use one of the <code>expectedFailure</code> methods - * in the surrounding <code>catch</code> block and this error will pass through it. */ - public static void shouldHaveFailedPreviously() { + * in the surrounding <code>catch</code> block and this error will pass through it. + * <p> + * This method throws, never returning normally, but declares a return type + * so you can pretend to throw the result, + * for instance if your calling code otherwise warns about needing to return something. */ + public static RuntimeException shouldHaveFailedPreviously() { throw new ShouldHaveFailedPreviouslyAssertionError(); } /** As {@link #shouldHaveFailedPreviously()} but allowing detail, http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/utils/common/src/main/java/org/apache/brooklyn/util/guava/AnyExceptionSupplier.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/guava/AnyExceptionSupplier.java b/utils/common/src/main/java/org/apache/brooklyn/util/guava/AnyExceptionSupplier.java index 7111c39..a194ac0 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/guava/AnyExceptionSupplier.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/AnyExceptionSupplier.java @@ -44,10 +44,10 @@ public class AnyExceptionSupplier<T extends Throwable> implements Supplier<T> { public T get() { String msg = message==null ? null : message.get(); Maybe<T> result = Maybe.absent(); - if (result.isAbsent() && msg==null && cause==null) result = Reflections.invokeConstructorWithArgs(type); - if (result.isAbsent() && cause==null) result = Reflections.invokeConstructorWithArgs(type, msg); - if (result.isAbsent() && msg==null) result = Reflections.invokeConstructorWithArgs(type, cause); - if (result.isAbsent()) result = Reflections.invokeConstructorWithArgs(type, msg, cause); + if (result.isAbsent() && msg==null && cause==null) result = Reflections.invokeConstructorFromArgs(type); + if (result.isAbsent() && cause==null) result = Reflections.invokeConstructorFromArgs(type, msg); + if (result.isAbsent() && msg==null) result = Reflections.invokeConstructorFromArgs(type, cause); + if (result.isAbsent()) result = Reflections.invokeConstructorFromArgs(type, msg, cause); if (result.isAbsent()) { throw new IllegalStateException("Cannot create desired "+type+" (missing constructor)", new IllegalStateException(message==null ? null : message.get(), cause)); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Boxing.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Boxing.java b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Boxing.java index 79a1830..87529ad 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Boxing.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Boxing.java @@ -23,7 +23,11 @@ import java.lang.reflect.Array; import org.apache.brooklyn.util.guava.Maybe; import com.google.common.collect.ImmutableBiMap; +import com.google.common.primitives.Primitives; +/** Conveniences for working with primitives and their boxed (wrapper) types. + * NB: there is redundancy with {@link Primitives} + */ public class Boxing { public static boolean unboxSafely(Boolean ref, boolean valueIfNull) { @@ -56,6 +60,17 @@ public class Boxing { } return Maybe.absent("Not a primitive: "+typeName); } + + /** returns name of primitive corresponding to the given (boxed or unboxed) type */ + public static Maybe<String> getPrimitiveName(Class<?> type) { + if (type!=null) { + if (PRIMITIVE_TO_BOXED.containsKey(type)) return Maybe.of(type.getName()); + if (PRIMITIVE_TO_BOXED.containsValue(type)) { + return Maybe.of(PRIMITIVE_TO_BOXED.inverse().get(type).getName()); + } + } + return Maybe.absent("Not a primitive or boxed primitive: "+type); + } public static Class<?> boxedType(Class<?> type) { if (PRIMITIVE_TO_BOXED.containsKey(type)) @@ -63,6 +78,20 @@ public class Boxing { return type; } + public static boolean isPrimitiveOrBoxedObject(Object o) { + if (o==null) return false; + return isPrimitiveOrBoxedClass(o.getClass()); + } + public static boolean isPrimitiveOrBoxedClass(Class<?> t) { + // TODO maybe better to switch to using Primitives, eg: + // return Primitives.allPrimitiveTypes().contains(type) || Primitives.allWrapperTypes().contains(type); + + if (t==null) return false; + if (t.isPrimitive()) return true; + if (PRIMITIVE_TO_BOXED.containsValue(t)) return true; + return false; + } + /** sets the given element in an array to the indicated value; * if the type is a primitive type, the appropriate primitive method is used * <p> http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Enums.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Enums.java b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Enums.java index d3bfd83..a9305a8 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Enums.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Enums.java @@ -71,8 +71,10 @@ public class Enums { return new EnumFromStringFunction<T>(type); } + /** returns array of values in the given enum, or null if it is not an enum */ @SuppressWarnings("unchecked") - private static <T extends Enum<?>> T[] values(Class<T> type) { + public static <T extends Enum<?>> T[] values(Class<T> type) { + if (type==null || !type.isEnum()) return null; try { return (T[]) type.getMethod("values").invoke(null); } catch (Exception e) { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/utils/common/src/main/java/org/apache/brooklyn/util/javalang/FieldOrderings.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/FieldOrderings.java b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/FieldOrderings.java new file mode 100644 index 0000000..ceb33e8 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/FieldOrderings.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.util.javalang; + +import java.lang.reflect.Field; +import java.util.Comparator; + +import org.apache.brooklyn.util.collections.MutableList; + +import com.google.common.collect.Ordering; + +public class FieldOrderings { + public static class FieldNameComparator implements Comparator<Field> { + private final Comparator<String> nameComparator; + public FieldNameComparator(Comparator<String> nameComparator) { this.nameComparator = nameComparator; } + @Override + public int compare(Field o1, Field o2) { + return nameComparator.compare(o1.getName(), o2.getName()); + } + } + public static class FieldClassComparator implements Comparator<Field> { + private final Comparator<Class<?>> classComparator; + public FieldClassComparator(Comparator<Class<?>> classComparator) { this.classComparator = classComparator; } + @Override + public int compare(Field o1, Field o2) { + return classComparator.compare(o1.getDeclaringClass(), o2.getDeclaringClass()); + } + } + + public static Comparator<Class<?>> SUB_BEST_CLASS_COMPARATOR = new SubbestClassComparator(); + private static class SubbestClassComparator implements Comparator<Class<?>> { + @Override + public int compare(Class<?> c1, Class<?> c2) { + Class<?> cS = Reflections.inferSubbest(c1, c2); + return (cS==c1 ? -1 : cS==c2 ? 1 : 0); + } + } + + /** Puts fields lower in the hierarchy first, and otherwise leaves fields in order */ + public static Comparator<Field> SUB_BEST_FIELD_FIST_THEN_DEFAULT = + new FieldClassComparator(SUB_BEST_CLASS_COMPARATOR); + /** Puts fields higher in the hierarchy first, and otherwise leaves fields in order */ + public static Comparator<Field> SUB_BEST_FIELD_LAST_THEN_DEFAULT = + new FieldClassComparator(Ordering.from(SUB_BEST_CLASS_COMPARATOR).reverse()); + /** Puts fields that are lower down the hierarchy first, and then sorts those alphabetically */ + @SuppressWarnings("unchecked") + public static Comparator<Field> SUB_BEST_FIELD_FIRST_THEN_ALPHABETICAL = Ordering.compound(MutableList.of( + new FieldClassComparator(SUB_BEST_CLASS_COMPARATOR), + new FieldNameComparator(Ordering.<String>natural()))); + /** Puts fields that are higher up in the hierarchy first, and then sorts those alphabetically */ + @SuppressWarnings("unchecked") + public static Comparator<Field> SUB_BEST_FIELD_LAST_THEN_ALPHABETICAL = Ordering.compound(MutableList.of( + new FieldClassComparator(Ordering.from(SUB_BEST_CLASS_COMPARATOR).reverse()), + new FieldNameComparator(Ordering.<String>natural()))); + /** Puts fields in alpha order, but in cases of duplicate those lower down the hierarchy are first */ + @SuppressWarnings("unchecked") + public static Comparator<Field> ALPHABETICAL_FIELD_THEN_SUB_BEST_FIRST = Ordering.compound(MutableList.of( + new FieldNameComparator(Ordering.<String>natural()), + new FieldClassComparator(SUB_BEST_CLASS_COMPARATOR))); + /** Puts fields in alpha order, but in cases of duplicate those higher up in the hierarchy are first + * (potentially confusing, as this will put masked fields first) */ + @SuppressWarnings("unchecked") + public static Comparator<Field> ALPHABETICAL_FIELD_THEN_SUB_BEST_LAST = Ordering.compound(MutableList.of( + new FieldNameComparator(Ordering.<String>natural()), + new FieldClassComparator(Ordering.from(SUB_BEST_CLASS_COMPARATOR).reverse()))); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/utils/common/src/main/java/org/apache/brooklyn/util/javalang/JavaClassNames.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/JavaClassNames.java b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/JavaClassNames.java index e9918df..fe8dd0c 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/JavaClassNames.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/JavaClassNames.java @@ -79,15 +79,23 @@ public class JavaClassNames { String result = ct.getSimpleName(); if (Strings.isBlank(result) || result.length()<=4) { - if (ct.isPrimitive()) { - // TODO unbox - } else { - result = ct.getName(); - } + result = ct.getName(); } return result+Strings.repeat("[]", arrayCount); } + /** as {@link #simpleClassName(Class)} but if something is an inner class it drops everything before the $ */ + public static String verySimpleClassName(Class<?> t) { + t = componentType(t); + String result = t.getSimpleName(); + result = result.substring(result.lastIndexOf('.')+1); + result = result.substring(result.lastIndexOf('$')+1); + if (Strings.isBlank(result)) { + result = t.getName(); + } + return result; + } + /** as {@link #simpleClassName(Class)} but taking the type of the object if it is not already a class * or a type-token; callers should usually do the getClass themselves, unless they aren't sure whether * it is already a Class-type object */ http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/utils/common/src/main/java/org/apache/brooklyn/util/javalang/ReflectionPredicates.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/ReflectionPredicates.java b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/ReflectionPredicates.java new file mode 100644 index 0000000..3395296 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/ReflectionPredicates.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.util.javalang; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; + +public class ReflectionPredicates { + + public static Predicate<Integer> MODIFIERS_PRIVATE = new ModifiersPrivate(); + private static class ModifiersPrivate implements Predicate<Integer> { + @Override public boolean apply(Integer modifiers) { return Modifier.isPrivate(modifiers); } + } + public static Predicate<Integer> MODIFIERS_PUBLIC = new ModifiersPublic(); + private static class ModifiersPublic implements Predicate<Integer> { + @Override public boolean apply(Integer modifiers) { return Modifier.isPublic(modifiers); } + } + public static Predicate<Integer> MODIFIERS_PROTECTED = new ModifiersProtected(); + private static class ModifiersProtected implements Predicate<Integer> { + @Override public boolean apply(Integer modifiers) { return Modifier.isProtected(modifiers); } + } + + public static Predicate<Integer> MODIFIERS_TRANSIENT = new ModifiersTransient(); + private static class ModifiersTransient implements Predicate<Integer> { + @Override public boolean apply(Integer modifiers) { return Modifier.isTransient(modifiers); } + } + public static Predicate<Integer> MODIFIERS_STATIC = new ModifiersStatic(); + private static class ModifiersStatic implements Predicate<Integer> { + @Override public boolean apply(Integer modifiers) { return Modifier.isStatic(modifiers); } + } + + public static Predicate<Field> fieldModifiers(Predicate<Integer> modifiersCheck) { return new FieldModifiers(modifiersCheck); } + private static class FieldModifiers implements Predicate<Field> { + private Predicate<Integer> modifiersCheck; + private FieldModifiers(Predicate<Integer> modifiersCheck) { this.modifiersCheck = modifiersCheck; } + @Override public boolean apply(Field f) { return modifiersCheck.apply(f.getModifiers()); } + } + public static Predicate<Field> IS_FIELD_PUBLIC = fieldModifiers(MODIFIERS_PUBLIC); + public static Predicate<Field> IS_FIELD_TRANSIENT = fieldModifiers(MODIFIERS_TRANSIENT); + public static Predicate<Field> IS_FIELD_NON_TRANSIENT = Predicates.not(IS_FIELD_TRANSIENT); + public static Predicate<Field> IS_FIELD_STATIC = fieldModifiers(MODIFIERS_STATIC); + public static Predicate<Field> IS_FIELD_NON_STATIC = Predicates.not(IS_FIELD_STATIC); + + public static Predicate<Method> methodModifiers(Predicate<Integer> modifiersCheck) { return new MethodModifiers(modifiersCheck); } + private static class MethodModifiers implements Predicate<Method> { + private Predicate<Integer> modifiersCheck; + private MethodModifiers(Predicate<Integer> modifiersCheck) { this.modifiersCheck = modifiersCheck; } + @Override public boolean apply(Method m) { return modifiersCheck.apply(m.getModifiers()); } + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java index 0f31882..7b2cba4 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java @@ -47,18 +47,20 @@ import javax.annotation.Nullable; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; +import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; /** - * Reflection utilities ("borrowed" from cloudsoft monterey). + * Reflection utilities * * @author aled */ @@ -88,7 +90,7 @@ public class Reflections { private final Map<String, String> classRenameMap = MutableMap.of(); public Reflections(ClassLoader classLoader) { - this.classLoader = checkNotNull(classLoader); + this.classLoader = classLoader!=null ? classLoader : getClass().getClassLoader(); } /** supply a map of known renames, of the form "old-class -> new-class" */ @@ -99,9 +101,9 @@ public class Reflections { public Object loadInstance(String classname, Object...argValues) throws ReflectionNotFoundException, ReflectionAccessException { Class<?> clazz = loadClass(classname); - Optional<?> v = null; + Maybe<?> v = null; try { - v = invokeConstructorWithArgs(clazz, argValues); + v = invokeConstructorFromArgs(clazz, argValues); if (v.isPresent()) return v.get(); } catch (Exception e) { throw new IllegalStateException("Error invoking constructor for "+clazz+Arrays.toString(argValues) + ": " + Exceptions.collapseText(e)); @@ -221,41 +223,80 @@ public class Reflections { } } - /** Invokes a suitable constructor, supporting varargs and primitives */ + /** @deprecated since 0.10.0 use {@link #invokeConstructorFromArgs(Class, Object...)} or one of the variants; + * this allows null field values */ @Deprecated public static <T> Optional<T> invokeConstructorWithArgs(ClassLoader classLoader, String className, Object...argsArray) { + return Reflections.<T>invokeConstructorFromArgsUntyped(classLoader, className, argsArray).toOptional(); + } + /** @deprecated since 0.10.0 use {@link #invokeConstructorFromArgs(Class, Object...)} or one of the variants */ @Deprecated + public static <T> Optional<T> invokeConstructorWithArgs(ClassLoader classLoader, Class<T> clazz, Object[] argsArray, boolean setAccessible) { + return invokeConstructorFromArgs(classLoader, clazz, argsArray, setAccessible).toOptional(); + } + /** @deprecated since 0.10.0 use {@link #invokeConstructorFromArgs(Class, Object...)} or one of the variants */ @Deprecated + public static <T> Optional<T> invokeConstructorWithArgs(Class<? extends T> clazz, Object...argsArray) { + return invokeConstructorFromArgs(clazz, argsArray).toOptional(); + } + /** @deprecated since 0.10.0 use {@link #invokeConstructorFromArgs(Class, Object...)} or one of the variants */ @Deprecated + public static <T> Optional<T> invokeConstructorWithArgs(Class<? extends T> clazz, Object[] argsArray, boolean setAccessible) { + return invokeConstructorFromArgs(clazz, argsArray, setAccessible).toOptional(); + } + /** @deprecated since 0.10.0 use {@link #invokeConstructorFromArgs(Class, Object...)} or one of the variants */ @Deprecated + public static <T> Optional<T> invokeConstructorWithArgs(Reflections reflections, Class<? extends T> clazz, Object[] argsArray, boolean setAccessible) { + return invokeConstructorFromArgs(reflections, clazz, argsArray, setAccessible).toOptional(); + } + + /** Finds and invokes a suitable constructor, supporting varargs and primitives, boxing and looking at compatible supertypes in the constructor's signature */ + public static <T> Maybe<T> invokeConstructorFromArgs(Class<? extends T> clazz, Object...argsArray) { + return invokeConstructorFromArgs(clazz, argsArray, false); + } + + /** As {@link #invokeConstructorFromArgs(Class, Object...)} but allowing more configurable input */ + public static Maybe<Object> invokeConstructorFromArgs(ClassLoader classLoader, String className, Object...argsArray) { + return invokeConstructorFromArgs(classLoader, null, className, argsArray); + } + + /** As {@link #invokeConstructorFromArgs(Class, Object...)} but allowing more configurable input */ + @SuppressWarnings("unchecked") + public static <T> Maybe<T> invokeConstructorFromArgs(ClassLoader classLoader, Class<T> optionalSupertype, String className, Object...argsArray) { Reflections reflections = new Reflections(classLoader); - @SuppressWarnings("unchecked") - Class<T> clazz = (Class<T>) reflections.loadClass(className); - return invokeConstructorWithArgs(reflections, clazz, argsArray, false); + Class<?> clazz = reflections.loadClass(className); + if (optionalSupertype!=null && !optionalSupertype.isAssignableFrom(clazz)) { + return Maybe.absent("The type requested '"+className+"' is not assignable to "+optionalSupertype); + } + return invokeConstructorFromArgs(reflections, (Class<T>)clazz, argsArray, false); } - /** Invokes a suitable constructor, supporting varargs and primitives */ - public static <T> Optional<T> invokeConstructorWithArgs(ClassLoader classLoader, Class<T> clazz, Object[] argsArray, boolean setAccessible) { + /** As {@link #invokeConstructorFromArgs(Class, Object...)} but allowing more configurable input */ + public static <T> Maybe<T> invokeConstructorFromArgsUntyped(ClassLoader classLoader, String className, Object...argsArray) { Reflections reflections = new Reflections(classLoader); - return invokeConstructorWithArgs(reflections, clazz, argsArray, setAccessible); + @SuppressWarnings("unchecked") + Class<T> clazz = (Class<T>)reflections.loadClass(className); + return invokeConstructorFromArgs(reflections, clazz, argsArray, false); } - /** Invokes a suitable constructor, supporting varargs and primitives */ - public static <T> Optional<T> invokeConstructorWithArgs(Class<T> clazz, Object...argsArray) { - return invokeConstructorWithArgs(clazz, argsArray, false); + /** As {@link #invokeConstructorFromArgs(Class, Object...)} but allowing more configurable input; + * in particular setAccessible allows private constructors to be used (not the default) */ + public static <T> Maybe<T> invokeConstructorFromArgs(ClassLoader classLoader, Class<T> clazz, Object[] argsArray, boolean setAccessible) { + Reflections reflections = new Reflections(classLoader); + return invokeConstructorFromArgs(reflections, clazz, argsArray, setAccessible); } - /** Invokes a suitable constructor, supporting varargs and primitives */ - public static <T> Optional<T> invokeConstructorWithArgs(Class<T> clazz, Object[] argsArray, boolean setAccessible) { - ClassLoader cl = clazz.getClassLoader(); - // if bootstrap class loader - if (cl == null) { - // The classloader isn't actually used so anything non-null will work - cl = ClassLoader.getSystemClassLoader(); - } - Reflections reflections = new Reflections(cl); - return invokeConstructorWithArgs(reflections, clazz, argsArray, setAccessible); + /** As {@link #invokeConstructorFromArgs(Class, Object...)} but allowing more configurable input; + * in particular setAccessible allows private constructors to be used (not the default) */ + public static <T> Maybe<T> invokeConstructorFromArgs(Class<? extends T> clazz, Object[] argsArray, boolean setAccessible) { + Reflections reflections = new Reflections(clazz.getClassLoader()); + return invokeConstructorFromArgs(reflections, clazz, argsArray, setAccessible); } - /** Invokes a suitable constructor, supporting varargs and primitives, additionally supporting setAccessible */ + /** As {@link #invokeConstructorFromArgs(Class, Object...)} but will use private constructors (with setAccessible = true) */ + public static <T> Maybe<T> invokeConstructorFromArgsIncludingPrivate(Class<? extends T> clazz, Object ...argsArray) { + return Reflections.invokeConstructorFromArgs(new Reflections(clazz.getClassLoader()), clazz, argsArray, true); + } + /** As {@link #invokeConstructorFromArgs(Class, Object...)} but allowing more configurable input; + * in particular setAccessible allows private constructors to be used (not the default) */ @SuppressWarnings("unchecked") - public static <T> Optional<T> invokeConstructorWithArgs(Reflections reflections, Class<T> clazz, Object[] argsArray, boolean setAccessible) { - for (Constructor<?> constructor : clazz.getConstructors()) { + public static <T> Maybe<T> invokeConstructorFromArgs(Reflections reflections, Class<? extends T> clazz, Object[] argsArray, boolean setAccessible) { + for (Constructor<?> constructor : MutableList.<Constructor<?>>of().appendAll(Arrays.asList(clazz.getConstructors())).appendAll(Arrays.asList(clazz.getDeclaredConstructors()))) { Class<?>[] parameterTypes = constructor.getParameterTypes(); if (constructor.isVarArgs()) { if (typesMatchUpTo(argsArray, parameterTypes, parameterTypes.length-1)) { @@ -277,16 +318,16 @@ public class Reflections { System.arraycopy(argsArray, 0, newArgsArray, 0, parameterTypes.length-1); newArgsArray[parameterTypes.length-1] = varargs; if (setAccessible) constructor.setAccessible(true); - return (Optional<T>) Optional.of(reflections.loadInstance(constructor, newArgsArray)); + return Maybe.of((T)reflections.loadInstance(constructor, newArgsArray)); } } } if (typesMatch(argsArray, parameterTypes)) { if (setAccessible) constructor.setAccessible(true); - return (Optional<T>) Optional.of(reflections.loadInstance(constructor, argsArray)); + return Maybe.of((T) reflections.loadInstance(constructor, argsArray)); } } - return Optional.absent(); + return Maybe.absent("Constructor not found"); } @@ -560,25 +601,86 @@ public class Reflections { throw toThrowIfFails; } + /** Finds the field with the given name declared on the given class or any superclass, + * using {@link Class#getDeclaredField(String)}. + * <p> + * If the field name contains a '.' the field is interpreted as having + * <code>DeclaringClassCanonicalName.FieldName</code> format, + * allowing a way to set a field unambiguously if some are masked. + * <p> + * @throws NoSuchFieldException if not found + */ public static Field findField(Class<?> clazz, String name) throws NoSuchFieldException { + return findFieldMaybe(clazz, name).orThrowUnwrapped(); + } + public static Maybe<Field> findFieldMaybe(Class<?> clazz, String originalName) { + String name = originalName; if (clazz == null || name == null) { throw new NullPointerException("Must not be null: clazz="+clazz+"; name="+name); } Class<?> clazzToInspect = clazz; NoSuchFieldException toThrowIfFails = null; + + String clazzRequired = null; + if (name.indexOf('.')>=0) { + int lastDotIndex = name.lastIndexOf('.'); + clazzRequired = name.substring(0, lastDotIndex); + name = name.substring(lastDotIndex+1); + } while (clazzToInspect != null) { try { - return clazzToInspect.getDeclaredField(name); + if (clazzRequired==null || clazzRequired.equals(clazzToInspect.getCanonicalName())) { + return Maybe.of(clazzToInspect.getDeclaredField(name)); + } } catch (NoSuchFieldException e) { if (toThrowIfFails == null) toThrowIfFails = e; - clazzToInspect = clazzToInspect.getSuperclass(); } + clazzToInspect = clazzToInspect.getSuperclass(); } - throw toThrowIfFails; + if (toThrowIfFails==null) return Maybe.absent("Field '"+originalName+"' not found"); + return Maybe.absent(toThrowIfFails); } + public static Maybe<Object> getFieldValueMaybe(Object instance, String fieldName) { + try { + if (instance==null) return null; + Field f = findField(instance.getClass(), fieldName); + return getFieldValueMaybe(instance, f); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + return Maybe.absent(e); + } + } + + public static Maybe<Object> getFieldValueMaybe(Object instance, Field field) { + try { + if (instance==null) return null; + if (field==null) return null; + field.setAccessible(true); + return Maybe.of(field.get(instance)); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + return Maybe.absent(e); + } + } + + /** Lists all public fields declared on the class or any ancestor, with those HIGHEST in the hierarchy first */ public static List<Field> findPublicFieldsOrderedBySuper(Class<?> clazz) { + return findFields(clazz, new Predicate<Field>() { + @Override public boolean apply(Field input) { + return Modifier.isPublic(input.getModifiers()); + }}, FieldOrderings.SUB_BEST_FIELD_LAST_THEN_DEFAULT); + } + + /** Lists all fields declared on the class, with those lowest in the hierarchy first, + * filtered and ordered as requested. + * <p> + * See {@link ReflectionPredicates} and {@link FieldOrderings} for conveniences. + * <p> + * Default is no filter and {@link FieldOrderings#SUB_BEST_FIELD_LAST_THEN_ALPHABETICAL} + * */ + public static List<Field> findFields(final Class<?> clazz, Predicate<Field> filter, Comparator<Field> fieldOrdering) { checkNotNull(clazz, "clazz"); MutableList.Builder<Field> result = MutableList.<Field>builder(); Stack<Class<?>> tovisit = new Stack<Class<?>>(); @@ -593,19 +695,12 @@ public class Reflections { if (nextclazz.getSuperclass() != null) tovisit.add(nextclazz.getSuperclass()); tovisit.addAll(Arrays.asList(nextclazz.getInterfaces())); - result.addAll(Iterables.filter(Arrays.asList(nextclazz.getDeclaredFields()), new Predicate<Field>() { - @Override public boolean apply(Field input) { - return Modifier.isPublic(input.getModifiers()); - }})); - + result.addAll(Iterables.filter(Arrays.asList(nextclazz.getDeclaredFields()), + filter!=null ? filter : Predicates.<Field>alwaysTrue())); } List<Field> resultList = result.build(); - Collections.sort(resultList, new Comparator<Field>() { - @Override public int compare(Field f1, Field f2) { - Field fsubbest = inferSubbestField(f1, f2); - return (fsubbest == null) ? 0 : (fsubbest == f1 ? 1 : -1); - }}); + Collections.sort(resultList, fieldOrdering != null ? fieldOrdering : FieldOrderings.SUB_BEST_FIELD_LAST_THEN_ALPHABETICAL); return resultList; } @@ -645,18 +740,25 @@ public class Reflections { } /** - * Gets the field that is in the sub-class; or null if one field does not come from a sub-class of the other field's class + * If the classes of the fields satisfy {@link #inferSubbest(Class, Class)} + * return the field in the lower (sub-best) class, otherwise null. */ public static Field inferSubbestField(Field f1, Field f2) { Class<?> c1 = f1.getDeclaringClass(); Class<?> c2 = f2.getDeclaringClass(); boolean isSuper1 = c1.isAssignableFrom(c2); boolean isSuper2 = c2.isAssignableFrom(c1); - return (isSuper1) ? (isSuper2 ? null : f2) : (isSuper2 ? f1 : null); + return (isSuper1) ? (isSuper2 ? + /* same field */ null : + /* f1 from super */ f2) : + (isSuper2 ? + /* f2 from super of f1 */ f1 : + /* fields are from different hierarchies */ null); } /** - * Gets the method that is in the sub-class; or null if one method does not come from a sub-class of the other method's class + * If the classes of the methods satisfy {@link #inferSubbest(Class, Class)} + * return the field in the lower (sub-best) class, otherwise null. */ public static Method inferSubbestMethod(Method m1, Method m2) { Class<?> c1 = m1.getDeclaringClass(); @@ -667,7 +769,8 @@ public class Reflections { } /** - * Gets the class that is in the sub-class; or null if neither is a sub-class of the other. + * If one class is a subclass of the other, return that (the lower in the type hierarchy); + * otherwise return null (if they are the same or neither is a subclass of the other). */ public static Class<?> inferSubbest(Class<?> c1, Class<?> c2) { boolean isSuper1 = c1.isAssignableFrom(c2); @@ -684,14 +787,25 @@ public class Reflections { return (T)candidate; } + /** @deprecated since 0.10.0 use {@link #invokeMethodFromArgs(Object, String, List)}; + * this allows null return values */ @Deprecated + public static Optional<Object> invokeMethodWithArgs(Object clazzOrInstance, String method, List<Object> args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + return invokeMethodWithArgs(clazzOrInstance, method, args, false); + } + /** @deprecated since 0.10.0 use {@link #invokeMethodFromArgs(Object, String, List)} */ @Deprecated + public static Optional<Object> invokeMethodWithArgs(Object clazzOrInstance, String method, List<Object> args, boolean setAccessible) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + return invokeMethodFromArgs(clazzOrInstance, method, args, setAccessible).toOptional(); + } + /** invokes the given method on the given clazz or instance, doing reasonably good matching on args etc * @throws InvocationTargetException * @throws IllegalAccessException * @throws IllegalArgumentException */ - public static Optional<Object> invokeMethodWithArgs(Object clazzOrInstance, String method, List<Object> args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { - return invokeMethodWithArgs(clazzOrInstance, method, args, false); + public static Maybe<Object> invokeMethodFromArgs(Object clazzOrInstance, String method, List<Object> args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + return invokeMethodFromArgs(clazzOrInstance, method, args, false); } - public static Optional<Object> invokeMethodWithArgs(Object clazzOrInstance, String method, List<Object> args, boolean setAccessible) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + /** as {@link #invokeMethodFromArgs(Object, String, List)} but giving control over whether to set it accessible */ + public static Maybe<Object> invokeMethodFromArgs(Object clazzOrInstance, String method, List<Object> args, boolean setAccessible) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { Preconditions.checkNotNull(clazzOrInstance, "clazz or instance"); Preconditions.checkNotNull(method, "method"); Preconditions.checkNotNull(args, "args to "+method); @@ -731,18 +845,18 @@ public class Reflections { System.arraycopy(argsArray, 0, newArgsArray, 0, parameterTypes.length-1); newArgsArray[parameterTypes.length-1] = varargs; if (setAccessible) m.setAccessible(true); - return Optional.of(m.invoke(instance, newArgsArray)); + return Maybe.of(m.invoke(instance, newArgsArray)); } } } if (typesMatch(argsArray, parameterTypes)) { if (setAccessible) m.setAccessible(true); - return Optional.of(m.invoke(instance, argsArray)); + return Maybe.of(m.invoke(instance, argsArray)); } } } - return Optional.absent(); + return Maybe.absent("Method not found matching given args"); } /** true iff all args match the corresponding types */ @@ -802,13 +916,18 @@ public class Reflections { return hasNoNonObjectFields(clazz.getSuperclass()); } - /** Takes a map of old-class-names to renames classes, and returns the mapped name if matched, or absent */ + /** @deprecated since 0.10.0 use {@link #findMappedNameMaybe(Map, String)} */ @Deprecated public static Optional<String> tryFindMappedName(Map<String, String> renames, String name) { - if (renames==null) return Optional.absent(); + return findMappedNameMaybe(renames, name).toOptional(); + } + + /** Takes a map of old-class-names to renames classes, and returns the mapped name if matched, or absent */ + public static Maybe<String> findMappedNameMaybe(Map<String, String> renames, String name) { + if (renames==null) return Maybe.absent("no renames supplied"); String mappedName = renames.get(name); if (mappedName != null) { - return Optional.of(mappedName); + return Maybe.of(mappedName); } // look for inner classes by mapping outer class @@ -816,20 +935,20 @@ public class Reflections { String outerClassName = name.substring(0, name.indexOf('$')); mappedName = renames.get(outerClassName); if (mappedName != null) { - return Optional.of(mappedName + name.substring(name.indexOf('$'))); + return Maybe.of(mappedName + name.substring(name.indexOf('$'))); } } - return Optional.absent(); + return Maybe.absent("mapped name not present"); } public static String findMappedNameAndLog(Map<String, String> renames, String name) { - Optional<String> rename = Reflections.tryFindMappedName(renames, name); + Maybe<String> rename = Reflections.findMappedNameMaybe(renames, name); if (rename.isPresent()) { LOG.debug("Mapping class '"+name+"' to '"+rename.get()+"'"); return rename.get(); } return name; } - + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Threads.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Threads.java b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Threads.java index 8e1b3d2..9d4625a 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Threads.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Threads.java @@ -23,7 +23,6 @@ import java.util.Collection; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/utils/common/src/test/java/org/apache/brooklyn/util/javalang/BoxingTest.java ---------------------------------------------------------------------- diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/javalang/BoxingTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/javalang/BoxingTest.java index 8b5a362..802fb22 100644 --- a/utils/common/src/test/java/org/apache/brooklyn/util/javalang/BoxingTest.java +++ b/utils/common/src/test/java/org/apache/brooklyn/util/javalang/BoxingTest.java @@ -35,4 +35,9 @@ public class BoxingTest { Assert.assertEquals(bt, Integer.class); } + @Test + public static void getPrimitive() { + Assert.assertEquals(Boxing.getPrimitiveName(Integer.class).get(), "int"); + } + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/23ab1c50/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java ---------------------------------------------------------------------- diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java index 2f0537c..b6bb63c 100644 --- a/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java +++ b/utils/common/src/test/java/org/apache/brooklyn/util/javalang/ReflectionsTest.java @@ -58,7 +58,8 @@ public class ReflectionsTest { @Test public void testConstructLangObject() { - Reflections.invokeConstructorWithArgs(java.util.Date.class); + // special test for this because the lang object might have classloader null + Assert.assertTrue(Reflections.invokeConstructorFromArgs(java.util.Date.class).get() instanceof java.util.Date); } public static interface MyInterface { @@ -123,15 +124,15 @@ public class ReflectionsTest { Method m = CI1.class.getMethod("m1", String.class, int.class, int.class, int[].class); Assert.assertEquals(m.invoke(null, "hello", 1, 2, new int[] { 3, 4}), "hello10"); - Assert.assertEquals(Reflections.invokeMethodWithArgs(CI1.class, "m1", Arrays.<Object>asList("hello", 3)).get(), "hello3"); - Assert.assertEquals(Reflections.invokeMethodWithArgs(CI1.class, "m1", Arrays.<Object>asList("hello", 3, 4, 5)).get(), "hello12"); + Assert.assertEquals(Reflections.invokeMethodFromArgs(CI1.class, "m1", Arrays.<Object>asList("hello", 3)).get(), "hello3"); + Assert.assertEquals(Reflections.invokeMethodFromArgs(CI1.class, "m1", Arrays.<Object>asList("hello", 3, 4, 5)).get(), "hello12"); } @Test public void testConstruction() throws Exception { - Assert.assertEquals(Reflections.invokeConstructorWithArgs(CI1.class, new Object[] {"hello", 3}).get().constructorArgs, ImmutableList.of("hello", 3)); - Assert.assertEquals(Reflections.invokeConstructorWithArgs(CI1.class, new Object[] {"hello", 3, 4, 5}).get().constructorArgs, ImmutableList.of("hello", 3, 4, 5)); - Assert.assertFalse(Reflections.invokeConstructorWithArgs(CI1.class, new Object[] {"wrong", "args"}).isPresent()); + Assert.assertEquals(Reflections.invokeConstructorFromArgs(CI1.class, new Object[] {"hello", 3}).get().constructorArgs, ImmutableList.of("hello", 3)); + Assert.assertEquals(Reflections.invokeConstructorFromArgs(CI1.class, new Object[] {"hello", 3, 4, 5}).get().constructorArgs, ImmutableList.of("hello", 3, 4, 5)); + Assert.assertFalse(Reflections.invokeConstructorFromArgs(CI1.class, new Object[] {"wrong", "args"}).isPresent()); } interface I { };
