You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sv...@apache.org on 2017/05/23 14:23:40 UTC
[2/6] brooklyn-server git commit: jclouds TypeCoercions for domain
objects
jclouds TypeCoercions for domain objects
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/1b23cb6b
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/1b23cb6b
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/1b23cb6b
Branch: refs/heads/master
Commit: 1b23cb6b6e7471258835b1f0e4820a78f9d5251f
Parents: 57ded18
Author: Aled Sage <al...@gmail.com>
Authored: Mon May 22 14:09:29 2017 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Tue May 23 14:45:33 2017 +0100
----------------------------------------------------------------------
.../location/jclouds/JcloudsLocation.java | 4 +-
.../jclouds/JcloudsLocationResolver.java | 6 +-
.../location/jclouds/JcloudsTypeCoercions.java | 168 +++++++++++
.../JcloudsTypeCoercionsWithBuilderTest.java | 250 +++++++++++++++++
.../JcloudsTypeCoercionsWithCreateTest.java | 278 +++++++++++++++++++
5 files changed, 704 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1b23cb6b/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 de71585..074ec5f 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
@@ -210,7 +210,9 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
@SetFromFlag // so it's persisted
private final Map<MachineLocation,String> vmInstanceIds = Maps.newLinkedHashMap();
- static { Networking.init(); }
+ static {
+ Networking.init();
+ }
public JcloudsLocation() {
super();
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1b23cb6b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationResolver.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationResolver.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationResolver.java
index aba0a3e..2c2f3ef 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationResolver.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationResolver.java
@@ -50,7 +50,11 @@ public class JcloudsLocationResolver implements LocationResolver {
// from http://docs.amazonwebservices.com/general/latest/gr/rande.html as of Apr 2012.
// it is suggested not to maintain this list here, instead to require aws-ec2 explicitly named.
"eu-west-1","us-east-1","us-west-1","us-west-2","ap-southeast-1","ap-northeast-1","sa-east-1");
-
+
+ static {
+ JcloudsTypeCoercions.init();
+ }
+
private ManagementContext managementContext;
@Override
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1b23cb6b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercions.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercions.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercions.java
new file mode 100644
index 0000000..56534ed
--- /dev/null
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercions.java
@@ -0,0 +1,168 @@
+/*
+ * 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.location.jclouds;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.brooklyn.util.core.flags.MethodCoercions;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.javalang.coerce.TryCoercer;
+import org.jclouds.json.SerializedNames;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+import com.google.common.reflect.TypeToken;
+
+public class JcloudsTypeCoercions {
+
+ private JcloudsTypeCoercions() {}
+
+ private static final AtomicBoolean initialized = new AtomicBoolean(false);
+
+ public static void init() {
+ synchronized (initialized) {
+ if (initialized.compareAndSet(false, true)) {
+ TypeCoercions.registerAdapter(new CoercionFromAutoValueBuilder());
+ TypeCoercions.registerAdapter(new CoercionFromAutoValueCreate());
+ }
+ }
+ }
+
+ static class CoercionFromAutoValueBuilder implements TryCoercer {
+ @Override
+ public <T> Maybe<T> tryCoerce(Object input, TypeToken<T> targetTypeToken) {
+ Class<? super T> targetType = targetTypeToken.getRawType();
+
+ // If we don't have a map of named params, we can't map it to builder methods
+ if (!(input instanceof Map)) {
+ return null;
+ }
+
+ Optional<Method> builderMethod = findBuilderMethod(targetType);
+ if (!builderMethod.isPresent()) return null;
+
+ Maybe<?> builder = MethodCoercions.tryFindAndInvokeMultiParameterMethod(targetType, ImmutableList.of(builderMethod.get()), ImmutableList.of());
+ if (builder.isAbsent()) {
+ return (Maybe<T>) (Maybe) builder;
+ }
+
+ Optional<Method> buildMethod = findBuildMethod(builder.get());
+ if (!buildMethod.isPresent()) {
+ return Maybe.absent("Builder for "+targetType.getCanonicalName()+" has no build() method");
+ }
+
+ for (Map.Entry<?, ?> entry : ((Map<?,?>)input).entrySet()) {
+ String key = (String) entry.getKey();
+ Object val = entry.getValue();
+
+ Maybe<?> invoked = MethodCoercions.tryFindAndInvokeBestMatchingMethod(builder.get(), key, val);
+ if (invoked.isAbsent()) {
+ RuntimeException cause = Maybe.Absent.getException(invoked);
+ return Maybe.absent("Builder for "+targetType.getCanonicalName()+" failed to call method for "+key, cause);
+ }
+ }
+
+ Maybe<?> result = MethodCoercions.tryFindAndInvokeMultiParameterMethod(builder.get(), ImmutableList.of(buildMethod.get()), ImmutableList.of());
+ if (result.isAbsent()) {
+ RuntimeException cause = Maybe.Absent.getException(result);
+ return Maybe.absent("Builder for "+targetType.getCanonicalName()+" failed to call build method", cause);
+ } else {
+ return (Maybe<T>) (Maybe) result;
+ }
+ }
+
+ private Optional<Method> findBuilderMethod(Class<?> clazz) {
+ for (Method m: clazz.getMethods()) {
+ if (((m.getModifiers()&Modifier.STATIC) == Modifier.STATIC) && m.getName().equals("builder")
+ && m.getParameterTypes().length == 0) {
+ return Optional.of(m);
+ }
+ }
+ return Optional.empty();
+ }
+
+ private Optional<Method> findBuildMethod(Object instance) {
+ for (Method m: instance.getClass().getMethods()) {
+ if (((m.getModifiers()&Modifier.STATIC) != Modifier.STATIC) && m.getName().equals("build")
+ && m.getParameterTypes().length == 0) {
+ return Optional.of(m);
+ }
+ }
+ return Optional.empty();
+ }
+ }
+
+ static class CoercionFromAutoValueCreate implements TryCoercer {
+ @Override
+ public <T> Maybe<T> tryCoerce(Object input, TypeToken<T> targetTypeToken) {
+ Class<? super T> targetType = targetTypeToken.getRawType();
+ Maybe<?> result = null;
+ Maybe<?> firstError = null;
+
+ // If we don't have a map of named params, we can't map it to "@SerializedNames"?
+ if (!(input instanceof Map)) {
+ return null;
+ }
+
+ Optional<Method> method = findCreateMethod(targetType);
+ if (!method.isPresent()) return null;
+
+ // Do we have a map of args, and need to look at the "@SerializedNames" annotation?
+ if (method.get().isAnnotationPresent(SerializedNames.class)) {
+ String[] argNames = method.get().getAnnotation(SerializedNames.class).value();
+
+ SetView<?> extraArgs = Sets.difference(((Map<?,?>)input).keySet(), ImmutableSet.copyOf(argNames));
+ if (!extraArgs.isEmpty()) {
+ return Maybe.absent("create() for "+targetType.getCanonicalName()+" does not accept extra args "+extraArgs);
+ }
+
+ List<Object> orderedArgs = Lists.newArrayList();
+ for (String argName : argNames) {
+ orderedArgs.add(((Map<?,?>)input).get(argName));
+ }
+ result = MethodCoercions.tryFindAndInvokeMultiParameterMethod(targetType, ImmutableList.of(method.get()), orderedArgs);
+ if (result != null && result.isPresent()) return Maybe.of((T)result.get());
+ if (result != null && firstError == null) firstError = result;
+ }
+
+ //not found
+ if (firstError != null) return (Maybe<T>) (Maybe) firstError;
+ return null;
+ }
+
+ private Optional<Method> findCreateMethod(Class<?> clazz) {
+ for (Method m: clazz.getMethods()) {
+ if (((m.getModifiers()&Modifier.STATIC) == Modifier.STATIC) && m.getName().equals("create")
+ && clazz.isAssignableFrom(m.getReturnType())) {
+ return Optional.of(m);
+ }
+ }
+ return Optional.empty();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1b23cb6b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercionsWithBuilderTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercionsWithBuilderTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercionsWithBuilderTest.java
new file mode 100644
index 0000000..f863102
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercionsWithBuilderTest.java
@@ -0,0 +1,250 @@
+/*
+ * 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.location.jclouds;
+
+import static org.apache.brooklyn.util.core.flags.TypeCoercions.coerce;
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.javalang.coerce.ClassCoercionException;
+import org.testng.annotations.Test;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+
+public class JcloudsTypeCoercionsWithBuilderTest {
+
+ static {
+ JcloudsTypeCoercions.init();
+ }
+
+ @Test
+ public void testCallsBuilder() {
+ assertEquals(
+ coerce(ImmutableMap.of("arg1", "val1", "arg2", "val2"), MyClazz.class),
+ MyClazz.builder().arg1("val1").arg2("val2").build());
+ assertEquals(
+ coerce(ImmutableMap.of("arg2", "val2", "arg1", "val1"), MyClazz.class),
+ MyClazz.builder().arg1("val1").arg2("val2").build());
+ assertEquals(
+ coerce(ImmutableMap.of("arg1", "val1"), MyClazz.class),
+ MyClazz.builder().arg1("val1").build());
+ assertEquals(
+ coerce(ImmutableMap.of("arg2", "val2"), MyClazz.class),
+ MyClazz.builder().arg2("val2").build());
+ }
+
+ @Test
+ public void testFailsIfExtraArgs() {
+ try {
+ coerce(ImmutableMap.of("arg1", "val1", "arg2", "val2", "arg3", "val3"), MyClazz.class);
+ Asserts.shouldHaveFailedPreviously();
+ } catch (ClassCoercionException e) {
+ Asserts.expectedFailureContains(e, "Builder for", "MyClazz", "failed to call method for arg3");
+ }
+ }
+
+ @Test
+ public void testFailsIfNoBuildMethod() {
+ try {
+ coerce(ImmutableMap.of("arg1", "val1"), MyClazzWithNoBuildMethod.class);
+ Asserts.shouldHaveFailedPreviously();
+ } catch (ClassCoercionException e) {
+ Asserts.expectedFailureContains(e, "Builder for", "MyClazzWithNoBuildMethod", "has no build() method");
+ }
+ }
+
+ @Test
+ public void testFailsIfNoNoargBuildMethod() {
+ try {
+ coerce(ImmutableMap.of("arg1", "val1"), MyClazzWithNoNoargBuildMethod.class);
+ Asserts.shouldHaveFailedPreviously();
+ } catch (ClassCoercionException e) {
+ Asserts.expectedFailureContains(e, "Builder for", "MyClazzWithNoNoargBuildMethod", "has no build() method");
+ }
+ }
+
+ @Test
+ public void testFailsIfNoNoargBuilderMethod() {
+ try {
+ coerce(ImmutableMap.of("arg1", "val1"), MyClazzWithNoNoargBuilderMethod.class);
+ Asserts.shouldHaveFailedPreviously();
+ } catch (ClassCoercionException e) {
+ Asserts.expectedFailureContains(e, "MyClazzWithNoNoargBuilderMethod", "no adapter known");
+ }
+ }
+
+ @Test
+ public void testCompositeOfCreatedObjs() {
+ assertEquals(
+ coerce(ImmutableMap.of("val",ImmutableMap.of("arg1", "val1", "arg2", "val2")), MyCompositeClazz.class),
+ MyCompositeClazz.builder().val((MyClazz.builder().arg1("val1").arg2("val2").build())).build());
+ }
+
+ public static class MyClazz {
+ private final String arg1;
+ private final String arg2;
+
+ public static class Builder {
+ private String arg1;
+ private String arg2;
+
+ public Builder arg1(String val) {
+ this.arg1 = val;
+ return this;
+ }
+ public Builder arg2(String val) {
+ this.arg2 = val;
+ return this;
+ }
+ public MyClazz build() {
+ return new MyClazz(arg1, arg2);
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private MyClazz(String arg1, String arg2) {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || obj.getClass() != getClass()) return false;
+ MyClazz o = (MyClazz) obj;
+ return Objects.equal(arg1, o.arg1) && Objects.equal(arg2, o.arg2);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(arg1, arg2);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("arg1", arg1).add("arg2", arg2).toString();
+ }
+ }
+
+ public static class MyCompositeClazz {
+ private final MyClazz val;
+
+ public static class Builder {
+ private MyClazz val;
+
+ public Builder val(MyClazz val) {
+ this.val = val;
+ return this;
+ }
+ public MyCompositeClazz build() {
+ return new MyCompositeClazz(val);
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private MyCompositeClazz(MyClazz val) {
+ this.val = val;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || obj.getClass() != getClass()) return false;
+ MyCompositeClazz o = (MyCompositeClazz) obj;
+ return Objects.equal(val, o.val);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(val);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("val", val).toString();
+ }
+ }
+
+ public static class MyClazzWithNoNoargBuilderMethod {
+ @SuppressWarnings("unused")
+ private final String arg1;
+
+ public static class Builder {
+ private String arg1;
+
+ public Builder arg1(String val) {
+ this.arg1 = val;
+ return this;
+ }
+ public MyClazzWithNoNoargBuilderMethod build() {
+ return new MyClazzWithNoNoargBuilderMethod(arg1);
+ }
+ }
+
+ public static Builder builder(String extraArg) {
+ return new Builder();
+ }
+
+ private MyClazzWithNoNoargBuilderMethod(String arg1) {
+ this.arg1 = arg1;
+ }
+ }
+
+ public static class MyClazzWithNoBuildMethod {
+ public static class Builder {
+ public Builder arg1(String val) {
+ return this;
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private MyClazzWithNoBuildMethod(String arg1) {
+ }
+ }
+
+ public static class MyClazzWithNoNoargBuildMethod {
+ public static class Builder {
+ private String arg1;
+
+ public Builder arg1(String val) {
+ this.arg1 = val;
+ return this;
+ }
+ public MyClazzWithNoNoargBuildMethod build(String extraArg) {
+ return new MyClazzWithNoNoargBuildMethod(arg1);
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private MyClazzWithNoNoargBuildMethod(String arg1) {
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1b23cb6b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercionsWithCreateTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercionsWithCreateTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercionsWithCreateTest.java
new file mode 100644
index 0000000..8adab07
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsTypeCoercionsWithCreateTest.java
@@ -0,0 +1,278 @@
+/*
+ * 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.location.jclouds;
+
+import static org.apache.brooklyn.util.core.flags.TypeCoercions.coerce;
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.javalang.coerce.ClassCoercionException;
+import org.jclouds.json.SerializedNames;
+import org.testng.annotations.Test;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class JcloudsTypeCoercionsWithCreateTest {
+
+ static {
+ JcloudsTypeCoercions.init();
+ }
+
+ @Test
+ public void testCallsCreate() {
+ assertEquals(
+ coerce(ImmutableMap.of("arg1", "val1", "arg2", "val2"), MyClazz.class),
+ MyClazz.create("val1", "val2"));
+ assertEquals(
+ coerce(ImmutableMap.of("arg2", "val2", "arg1", "val1"), MyClazz.class),
+ MyClazz.create("val1", "val2"));
+ assertEquals(
+ coerce(ImmutableMap.of("arg1", "val1"), MyClazz.class),
+ MyClazz.create("val1", null));
+ assertEquals(
+ coerce(ImmutableMap.of("arg2", "val2"), MyClazz.class),
+ MyClazz.create(null, "val2"));
+ }
+
+ @Test
+ public void testFailsIfExtraArgs() {
+ try {
+ coerce(ImmutableMap.of("arg1", "val1", "arg2", "val2", "arg3", "val3"), MyClazz.class);
+ Asserts.shouldHaveFailedPreviously();
+ } catch (ClassCoercionException e) {
+ Asserts.expectedFailureContains(e, "create()", "MyClazz", "does not accept extra args [arg3]");
+ }
+ }
+
+ @Test
+ public void testCallsCreateWithPrimitives() {
+ assertEquals(
+ coerce(ImmutableMap.builder().put("boolArg", true).put("byteArg", (byte)1).put("shortArg", (short)2)
+ .put("intArg", (int)3).put("longArg", (long)4).put("floatArg", (float)5.0)
+ .put("doubleArg", (double)6.0).build(), MyClazzWithPrimitives.class),
+ MyClazzWithPrimitives.create(true, (byte)1, (short)2, (int)3, (long)4, (float)5.0, (double)6.0));
+ assertEquals(
+ coerce(ImmutableMap.builder().put("boolArg", "true").put("byteArg", "1").put("shortArg", "2")
+ .put("intArg", "3").put("longArg", "4").put("floatArg", "5.0")
+ .put("doubleArg", "6.0").build(), MyClazzWithPrimitives.class),
+ MyClazzWithPrimitives.create(true, (byte)1, (short)2, (int)3, (long)4, (float)5.0, (double)6.0));
+ }
+ @Test
+ public void testListOfCreatedObjs() {
+ assertEquals(
+ coerce(ImmutableMap.of("vals", ImmutableList.of()), ListOfMyClazz.class),
+ ListOfMyClazz.create(ImmutableList.of()));
+ assertEquals(
+ coerce(ImmutableMap.of("vals", ImmutableList.of(ImmutableMap.of("arg1", "val1", "arg2", "val2"))), ListOfMyClazz.class),
+ ListOfMyClazz.create(ImmutableList.of(MyClazz.create("val1", "val2"))));
+ }
+
+ @Test
+ public void testCompositeOfCreatedObjs() {
+ assertEquals(
+ coerce(ImmutableMap.of("val",ImmutableMap.of("arg1", "val1", "arg2", "val2")), MyCompositeClazz.class),
+ MyCompositeClazz.create(MyClazz.create("val1", "val2")));
+ }
+
+ @Test
+ public void testMapOfCreatedObjs() {
+ assertEquals(
+ coerce(ImmutableMap.of("vals", ImmutableMap.of()), MapOfMyClazz.class),
+ MapOfMyClazz.create(ImmutableMap.of()));
+ assertEquals(
+ coerce(ImmutableMap.of("vals", ImmutableMap.of("key1", ImmutableMap.of("arg1", "val1", "arg2", "val2"))), MapOfMyClazz.class),
+ MapOfMyClazz.create(ImmutableMap.of("key1", MyClazz.create("val1", "val2"))));
+ }
+
+ public static class MyClazz {
+ private final String arg1;
+ private final String arg2;
+
+ @SerializedNames({"arg1", "arg2"})
+ public static MyClazz create(String arg1, String arg2) {
+ return new MyClazz(arg1, arg2);
+ }
+
+ private MyClazz(String arg1, String arg2) {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof MyClazz)) return false;
+ MyClazz o = (MyClazz) obj;
+ return Objects.equal(arg1, o.arg1) && Objects.equal(arg2, o.arg2);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(arg1, arg2);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("arg1", arg1).add("arg2", arg2).toString();
+ }
+ }
+
+ public static class MyCompositeClazz {
+ private final MyClazz val;
+
+ @SerializedNames({"val"})
+ public static MyCompositeClazz create(MyClazz val) {
+ return new MyCompositeClazz(val);
+ }
+
+ private MyCompositeClazz(MyClazz val) {
+ this.val = val;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof MyCompositeClazz)) return false;
+ MyCompositeClazz o = (MyCompositeClazz) obj;
+ return Objects.equal(val, o.val);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(val);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("val", val).toString();
+ }
+ }
+
+ public static class MyClazzWithPrimitives {
+ private final boolean boolArg;
+ private final byte byteArg;
+ private final short shortArg;
+ private final int intArg;
+ private final long longArg;
+ private final float floatArg;
+ private final double doubleArg;
+
+ @SerializedNames({"boolArg", "byteArg", "shortArg", "intArg", "longArg", "floatArg", "doubleArg"})
+ public static MyClazzWithPrimitives create(boolean boolArg, byte byteArg, short shortArg, int intArg, long longArg, float floatArg, double doubleArg) {
+ return new MyClazzWithPrimitives(boolArg, byteArg, shortArg, intArg, longArg, floatArg, doubleArg);
+ }
+
+ private MyClazzWithPrimitives(boolean boolArg, byte byteArg, short shortArg, int intArg, long longArg, float floatArg, double doubleArg) {
+ this.boolArg = boolArg;
+ this.byteArg = byteArg;
+ this.shortArg = shortArg;
+ this.intArg = intArg;
+ this.longArg = longArg;
+ this.floatArg = floatArg;
+ this.doubleArg = doubleArg;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof MyClazzWithPrimitives)) return false;
+ MyClazzWithPrimitives o = (MyClazzWithPrimitives) obj;
+ return Objects.equal(boolArg, o.boolArg) && Objects.equal(byteArg, o.byteArg)
+ && Objects.equal(shortArg, o.shortArg) && Objects.equal(intArg, o.intArg)
+ && Objects.equal(longArg, o.longArg) && Objects.equal(floatArg, o.floatArg)
+ && Objects.equal(doubleArg, o.doubleArg);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(boolArg, byteArg, shortArg, intArg, longArg, floatArg, doubleArg);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("boolArg", boolArg).add("byteArg", byteArg)
+ .add("shortArg", shortArg).add("intArg", intArg).add("longArg", longArg)
+ .add("floatArg", floatArg).add("doubleArg", doubleArg)
+ .toString();
+ }
+ }
+
+ public static class ListOfMyClazz {
+ private final List<MyClazz> vals;
+
+ @SerializedNames({"vals"})
+ public static ListOfMyClazz create(List<MyClazz> vals) {
+ return new ListOfMyClazz(vals);
+ }
+
+ private ListOfMyClazz(List<MyClazz> vals) {
+ this.vals = vals;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ListOfMyClazz)) return false;
+ ListOfMyClazz o = (ListOfMyClazz) obj;
+ return Objects.equal(vals, o.vals);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(vals);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("vals", vals).toString();
+ }
+ }
+
+ public static class MapOfMyClazz {
+ private final Map<String, MyClazz> vals;
+
+ @SerializedNames({"vals"})
+ public static MapOfMyClazz create(Map<String, MyClazz> vals) {
+ return new MapOfMyClazz(vals);
+ }
+
+ private MapOfMyClazz(Map<String, MyClazz> vals) {
+ this.vals = vals;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof MapOfMyClazz)) return false;
+ MapOfMyClazz o = (MapOfMyClazz) obj;
+ return Objects.equal(vals, o.vals);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(vals);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("vals", vals).toString();
+ }
+ }
+}