You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2019/08/02 17:28:32 UTC
[juneau] branch master updated: JUNEAU-128 Code improvements around
DynamicSwaps
This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 5420870 JUNEAU-128 Code improvements around DynamicSwaps
5420870 is described below
commit 5420870b6994d1ae0521314c3b6334d96d7bbd48
Author: JamesBognar <ja...@apache.org>
AuthorDate: Fri Aug 2 13:28:17 2019 -0400
JUNEAU-128 Code improvements around DynamicSwaps
---
.../apache/juneau/reflection/ClassInfoTest.java | 2 +-
.../juneau/reflection/ExecutableInfoTest.java | 32 +-
.../apache/juneau/transform/AutoListSwapTest.java | 360 ++++++++++
.../apache/juneau/transform/AutoMapSwapTest.java | 360 ++++++++++
.../juneau/transform/AutoNumberSwapTest.java | 797 +++++++++++++++++++++
.../juneau/transform/AutoObjectSwapTest.java | 353 +++++++++
.../juneau/transform/AutoStringSwapTest.java | 271 +++++++
.../apache/juneau/BeanProxyInvocationHandler.java | 2 +-
.../src/main/java/org/apache/juneau/ClassMeta.java | 25 +-
.../org/apache/juneau/annotation/BeanIgnore.java | 2 +-
.../org/apache/juneau/internal/ClassUtils.java | 29 +-
.../apache/juneau/internal/CollectionUtils.java | 11 +
.../org/apache/juneau/parser/ParseException.java | 21 +
.../java/org/apache/juneau/reflect/ClassInfo.java | 33 +-
.../org/apache/juneau/reflect/ExecutableInfo.java | 73 +-
.../java/org/apache/juneau/reflect/MethodInfo.java | 22 +-
.../juneau/serializer/SerializeException.java | 22 +-
.../org/apache/juneau/transform/AutoListSwap.java | 182 +++++
.../org/apache/juneau/transform/AutoMapSwap.java | 182 +++++
.../apache/juneau/transform/AutoNumberSwap.java | 222 ++++++
.../apache/juneau/transform/AutoObjectSwap.java | 183 +++++
.../apache/juneau/transform/AutoStringSwap.java | 147 ++++
.../org/apache/juneau/transform/DynamicSwaps.java | 129 ----
.../11.Transforms/02.DefaultPojoSwaps.html | 2 +-
24 files changed, 3290 insertions(+), 172 deletions(-)
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
index cb909e1..30c51a2 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
@@ -1898,7 +1898,7 @@ public class ClassInfoTest {
@Test
public void isChildOf_null() {
- assertFalse(ka.isChildOf(null));
+ assertFalse(ka.isChildOf((Class<?>)null));
}
@Test
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java
index 64d8287..dd90556 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java
@@ -472,30 +472,30 @@ public class ExecutableInfoTest {
@Test
public void hasArgs() {
- assertTrue(e_hasParams.hasArgs(int.class));
- assertFalse(e_hasParams.hasArgs());
- assertFalse(e_hasParams.hasArgs(long.class));
- assertTrue(e_hasNoParams.hasArgs());
- assertFalse(e_hasNoParams.hasArgs(long.class));
+ assertTrue(e_hasParams.hasParamTypes(int.class));
+ assertFalse(e_hasParams.hasParamTypes(new Class[0]));
+ assertFalse(e_hasParams.hasParamTypes(long.class));
+ assertTrue(e_hasNoParams.hasParamTypes(new Class[0]));
+ assertFalse(e_hasNoParams.hasParamTypes(long.class));
}
@Test
public void hasArgParents() {
- assertTrue(e_hasStringParam.hasArgParents(String.class));
- assertTrue(e_hasStringParam.hasArgParents(CharSequence.class));
- assertFalse(e_hasStringParam.hasArgParents(StringBuilder.class));
- assertFalse(e_hasStringParam.hasArgParents());
- assertFalse(e_hasStringParam.hasArgParents(String.class, String.class));
- assertFalse(e_hasStringParam.hasArgParents(long.class));
+ assertTrue(e_hasStringParam.hasParamTypeParents(String.class));
+ assertTrue(e_hasStringParam.hasParamTypeParents(CharSequence.class));
+ assertFalse(e_hasStringParam.hasParamTypeParents(StringBuilder.class));
+ assertFalse(e_hasStringParam.hasParamTypeParents(new Class[0]));
+ assertFalse(e_hasStringParam.hasParamTypeParents(String.class, String.class));
+ assertFalse(e_hasStringParam.hasParamTypeParents(long.class));
}
@Test
public void hasFuzzyArgs() {
- assertTrue(e_hasParams.hasFuzzyArgs(int.class));
- assertTrue(e_hasParams.hasFuzzyArgs(int.class, long.class));
- assertFalse(e_hasParams.hasFuzzyArgs(long.class));
- assertTrue(e_hasNoParams.hasFuzzyArgs());
- assertTrue(e_hasNoParams.hasFuzzyArgs(long.class));
+ assertTrue(e_hasParams.hasFuzzyParamTypes(int.class));
+ assertTrue(e_hasParams.hasFuzzyParamTypes(int.class, long.class));
+ assertFalse(e_hasParams.hasFuzzyParamTypes(long.class));
+ assertTrue(e_hasNoParams.hasFuzzyParamTypes(new Class[0]));
+ assertTrue(e_hasNoParams.hasFuzzyParamTypes(long.class));
}
@Test
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoListSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoListSwapTest.java
new file mode 100644
index 0000000..3655367
--- /dev/null
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoListSwapTest.java
@@ -0,0 +1,360 @@
+// ***************************************************************************************************************************
+// * 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.juneau.transform;
+
+import static org.junit.Assert.*;
+import static org.apache.juneau.testutils.TestUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@SuppressWarnings({"unchecked","rawtypes"})
+public class AutoListSwapTest {
+
+ private static final List<String> STRINGLIST = AList.create("foo");
+ private static final ObjectList OBJECTLIST = new ObjectList().append("foo");
+
+ private static PojoSwap find(Class<?> c) {
+ return AutoListSwap.find(ClassInfo.of(c));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Swap methods
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class A01 {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+ public static class A02 {
+ public ObjectList toObjectList() {
+ return OBJECTLIST;
+ }
+ }
+ public static class A03 {
+ public ObjectList toObjectList() throws SerializeException {
+ throw new SerializeException("foo");
+ }
+ }
+ public static class A04 {
+ public ObjectList toObjectList() {
+ throw new RuntimeException("foo");
+ }
+ }
+
+ @Test
+ public void a01_swap_toList() throws Exception {
+ assertObjectEquals("['foo']", find(A01.class).swap(null, new A01()));
+ }
+
+ @Test
+ public void a02_swap_toObjectList() throws Exception {
+ assertObjectEquals("['foo']", find(A02.class).swap(null, new A02()));
+ }
+
+ @Test(expected = SerializeException.class)
+ public void a03_swap_serializeException() throws Exception {
+ find(A03.class).swap(null, null);
+ }
+
+ @Test(expected = SerializeException.class)
+ public void a04_swap_runtimeException() throws Exception {
+ find(A04.class).swap(null, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Unswap methods
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class B01 {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ public static B01 fromList(List<String> o) {
+ assertObjectEquals("['foo']", o);
+ return new B01();
+ }
+ }
+ public static class B02 {
+ public ObjectList toObjectList() {
+ return OBJECTLIST;
+ }
+ public static B02 fromObjectList(ObjectList o) {
+ assertObjectEquals("['foo']", o);
+ return new B02();
+ }
+ }
+ public static class B03 {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ public static B03 create(List<String> o) {
+ assertObjectEquals("['foo']", o);
+ return new B03();
+ }
+ }
+ public static class B04 {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+
+ @Test
+ public void b01_unswap_fromList() throws Exception {
+ assertNotNull(find(B01.class).unswap(null, STRINGLIST, null));
+ }
+
+ @Test
+ public void b02_unswap_fromObjectList() throws Exception {
+ assertNotNull(find(B02.class).unswap(null, OBJECTLIST, null));
+ }
+
+ @Test
+ public void b03_unswap_create() throws Exception {
+ assertNotNull(find(B03.class).unswap(null, STRINGLIST, null));
+ }
+
+ @Test(expected = ParseException.class)
+ public void b04_unswap_noMethod() throws Exception {
+ find(B04.class).unswap(null, STRINGLIST, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Unswap constructor
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class C01 {
+ public C01() {}
+ public C01(List<String> o) {
+ assertObjectEquals("['foo']", o);
+ }
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+
+ @Test
+ public void c01_unswap_constructor() throws Exception {
+ assertNotNull(find(C01.class).unswap(null, STRINGLIST, null));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore class
+ //------------------------------------------------------------------------------------------------------------------
+
+ @BeanIgnore
+ public static class D01 {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+ public static class D02 {
+ public class D02A {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+ }
+
+ @Test
+ public void d01_ignoreClass_beanIgnore() throws Exception {
+ assertNull(find(D01.class));
+ }
+
+ @Test
+ public void d02_ignoreClass_memberClass() throws Exception {
+ assertNull(find(D02.D02A.class));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore swap method
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class E01 {
+ @BeanIgnore
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+ public static class E02 {
+ @Deprecated
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+ public static class E03 {
+ public Object toList() {
+ return STRINGLIST;
+ }
+ }
+ public static class E04 {
+ public List<String> toList(List<String> foo) {
+ return STRINGLIST;
+ }
+ }
+ public static class E05 {
+ public static List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+
+ @Test
+ public void e01_ignoreSwapMethod_beanIgnore() throws Exception {
+ assertNull(find(E01.class));
+ }
+
+ @Test
+ public void e02_ignoreSwapMethod_deprecated() throws Exception {
+ assertNull(find(E02.class));
+ }
+
+ @Test
+ public void e03_ignoreSwapMethod_wrongReturnType() throws Exception {
+ assertNull(find(E03.class));
+ }
+
+ @Test
+ public void e04_ignoreSwapMethod_wrongParameters() throws Exception {
+ assertNull(find(E04.class));
+ }
+
+ @Test
+ public void e05_ignoreSwapMethod_notStatic() throws Exception {
+ assertNull(find(E05.class));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore unswap method
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class F01 {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ @BeanIgnore
+ public static F01 create(List<String> o) {
+ return null;
+ }
+ }
+ public static class F02 {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ @Deprecated
+ public static F02 create(List<String> o) {
+ return null;
+ }
+ }
+ public static class F03 {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ public static Object create(List<String> o) {
+ return null;
+ }
+ }
+ public static class F04 {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ public static F04 create(Map<String,String> o) {
+ return null;
+ }
+ }
+ public static class F05 {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ public F05 create(List<String> o) {
+ return null;
+ }
+ }
+ public static class F06 {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ public static F06 createx(List<String> o) {
+ return null;
+ }
+ }
+
+ @Test(expected = ParseException.class)
+ public void f01_ignoreUnswapMethod_beanIgnore() throws Exception {
+ find(F01.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f02_ignoreUnswapMethod_deprecated() throws Exception {
+ find(F02.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f03_ignoreUnswapMethod_wrongReturnType() throws Exception {
+ find(F03.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f04_ignoreUnswapMethod_wrongParameters() throws Exception {
+ find(F04.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f05_ignoreUnswapMethod_notStatic() throws Exception {
+ find(F05.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f06_ignoreUnswapMethod_wrongName() throws Exception {
+ find(F06.class).unswap(null, null, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore constructor
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class G01 {
+ @BeanIgnore
+ public G01(List<String> o) {}
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+
+ public static class G02 {
+ @Deprecated
+ public G02(List<String> o) {}
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+
+ @Test(expected = ParseException.class)
+ public void g01_ignoreUnswapConstructor_beanIgnore() throws Exception {
+ find(G01.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
+ find(G02.class).unswap(null, null, null);
+ }
+}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoMapSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoMapSwapTest.java
new file mode 100644
index 0000000..c32fa0f
--- /dev/null
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoMapSwapTest.java
@@ -0,0 +1,360 @@
+// ***************************************************************************************************************************
+// * 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.juneau.transform;
+
+import static org.apache.juneau.testutils.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@SuppressWarnings({"unchecked","rawtypes"})
+public class AutoMapSwapTest {
+
+ private static final Map<String,String> STRINGMAP = AMap.<String,String>create().append("foo","bar");
+ private static final ObjectMap OBJECTMAP = new ObjectMap().append("foo","bar");
+
+ private static PojoSwap find(Class<?> c) {
+ return AutoMapSwap.find(ClassInfo.of(c));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Swap methods
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class A01 {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
+ public static class A02 {
+ public ObjectMap toObjectMap() {
+ return OBJECTMAP;
+ }
+ }
+ public static class A03 {
+ public ObjectMap toObjectMap() throws SerializeException {
+ throw new SerializeException("foo");
+ }
+ }
+ public static class A04 {
+ public ObjectMap toObjectMap() {
+ throw new RuntimeException("foo");
+ }
+ }
+
+ @Test
+ public void a01_swap_toMap() throws Exception {
+ assertObjectEquals("{foo:'bar'}", find(A01.class).swap(null, new A01()));
+ }
+
+ @Test
+ public void a02_swap_toObjectMap() throws Exception {
+ assertObjectEquals("{foo:'bar'}", find(A02.class).swap(null, new A02()));
+ }
+
+ @Test(expected = SerializeException.class)
+ public void a03_swap_serializeException() throws Exception {
+ find(A03.class).swap(null, null);
+ }
+
+ @Test(expected = SerializeException.class)
+ public void a04_swap_runtimeException() throws Exception {
+ find(A04.class).swap(null, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Unswap methods
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class B01 {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ public static B01 fromMap(Map<String,String> o) {
+ assertObjectEquals("{foo:'bar'}", o);
+ return new B01();
+ }
+ }
+ public static class B02 {
+ public ObjectMap toObjectMap() {
+ return OBJECTMAP;
+ }
+ public static B02 fromObjectMap(ObjectMap o) {
+ assertObjectEquals("{foo:'bar'}", o);
+ return new B02();
+ }
+ }
+ public static class B03 {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ public static B03 create(Map<String,String> o) {
+ assertObjectEquals("{foo:'bar'}", o);
+ return new B03();
+ }
+ }
+ public static class B04 {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
+
+ @Test
+ public void b01_unswap_fromMap() throws Exception {
+ assertNotNull(find(B01.class).unswap(null, STRINGMAP, null));
+ }
+
+ @Test
+ public void b02_unswap_fromObjectMap() throws Exception {
+ assertNotNull(find(B02.class).unswap(null, OBJECTMAP, null));
+ }
+
+ @Test
+ public void b03_unswap_create() throws Exception {
+ assertNotNull(find(B03.class).unswap(null, STRINGMAP, null));
+ }
+
+ @Test(expected = ParseException.class)
+ public void b04_unswap_noMethod() throws Exception {
+ find(B04.class).unswap(null, STRINGMAP, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Unswap constructor
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class C01 {
+ public C01() {}
+ public C01(Map<String,String> o) {
+ assertObjectEquals("{foo:'bar'}", o);
+ }
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
+
+ @Test
+ public void c01_unswap_constructor() throws Exception {
+ assertNotNull(find(C01.class).unswap(null, STRINGMAP, null));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore class
+ //------------------------------------------------------------------------------------------------------------------
+
+ @BeanIgnore
+ public static class D01 {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
+ public static class D02 {
+ public class D02A {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
+ }
+
+ @Test
+ public void d01_ignoreClass_beanIgnore() throws Exception {
+ assertNull(find(D01.class));
+ }
+
+ @Test
+ public void d02_ignoreClass_memberClass() throws Exception {
+ assertNull(find(D02.D02A.class));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore swap method
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class E01 {
+ @BeanIgnore
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
+ public static class E02 {
+ @Deprecated
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
+ public static class E03 {
+ public Object toMap() {
+ return STRINGMAP;
+ }
+ }
+ public static class E04 {
+ public Map<String,String> toMap(Map<String,String> foo) {
+ return STRINGMAP;
+ }
+ }
+ public static class E05 {
+ public static Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
+
+ @Test
+ public void e01_ignoreSwapMethod_beanIgnore() throws Exception {
+ assertNull(find(E01.class));
+ }
+
+ @Test
+ public void e02_ignoreSwapMethod_deprecated() throws Exception {
+ assertNull(find(E02.class));
+ }
+
+ @Test
+ public void e03_ignoreSwapMethod_wrongReturnType() throws Exception {
+ assertNull(find(E03.class));
+ }
+
+ @Test
+ public void e04_ignoreSwapMethod_wrongParameters() throws Exception {
+ assertNull(find(E04.class));
+ }
+
+ @Test
+ public void e05_ignoreSwapMethod_notStatic() throws Exception {
+ assertNull(find(E05.class));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore unswap method
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class F01 {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ @BeanIgnore
+ public static F01 create(Map<String,String> o) {
+ return null;
+ }
+ }
+ public static class F02 {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ @Deprecated
+ public static F02 create(Map<String,String> o) {
+ return null;
+ }
+ }
+ public static class F03 {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ public static Object create(Map<String,String> o) {
+ return null;
+ }
+ }
+ public static class F04 {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ public static F04 create(List<String> o) {
+ return null;
+ }
+ }
+ public static class F05 {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ public F05 create(Map<String,String> o) {
+ return null;
+ }
+ }
+ public static class F06 {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ public static F06 createx(Map<String,String> o) {
+ return null;
+ }
+ }
+
+ @Test(expected = ParseException.class)
+ public void f01_ignoreUnswapMethod_beanIgnore() throws Exception {
+ find(F01.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f02_ignoreUnswapMethod_deprecated() throws Exception {
+ find(F02.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f03_ignoreUnswapMethod_wrongReturnType() throws Exception {
+ find(F03.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f04_ignoreUnswapMethod_wrongParameters() throws Exception {
+ find(F04.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f05_ignoreUnswapMethod_notStatic() throws Exception {
+ find(F05.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f06_ignoreUnswapMethod_wrongName() throws Exception {
+ find(F06.class).unswap(null, null, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore constructor
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class G01 {
+ @BeanIgnore
+ public G01(Map<String,String> o) {}
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
+
+ public static class G02 {
+ @Deprecated
+ public G02(Map<String,String> o) {}
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
+
+ @Test(expected = ParseException.class)
+ public void g01_ignoreUnswapConstructor_beanIgnore() throws Exception {
+ find(G01.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
+ find(G02.class).unswap(null, null, null);
+ }
+}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoNumberSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoNumberSwapTest.java
new file mode 100644
index 0000000..4415e78
--- /dev/null
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoNumberSwapTest.java
@@ -0,0 +1,797 @@
+// ***************************************************************************************************************************
+// * 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.juneau.transform;
+
+import static org.apache.juneau.testutils.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@SuppressWarnings({"unchecked","rawtypes"})
+public class AutoNumberSwapTest {
+
+ private static PojoSwap find(Class<?> c) {
+ return AutoNumberSwap.find(ClassInfo.of(c));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Swap methods
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class A01 {
+ public Number toNumber() {
+ return 1;
+ }
+ }
+ public static class A02 {
+ public Integer toInteger() {
+ return 1;
+ }
+ }
+ public static class A03 {
+ public int toInt() {
+ return 1;
+ }
+ }
+ public static class A04 {
+ public Long toLong() {
+ return 1l;
+ }
+ }
+ public static class A05 {
+ public long toLong() {
+ return 1l;
+ }
+ }
+ public static class A06 {
+ public Float toFloat() {
+ return 1f;
+ }
+ }
+ public static class A07 {
+ public float toFloat() {
+ return 1f;
+ }
+ }
+ public static class A08 {
+ public Double toDouble() {
+ return 1d;
+ }
+ }
+ public static class A09 {
+ public double toDouble() {
+ return 1d;
+ }
+ }
+ public static class A10 {
+ public Short toShort() {
+ return 1;
+ }
+ }
+ public static class A11 {
+ public short toShort() {
+ return 1;
+ }
+ }
+ public static class A12 {
+ public Byte toByte() {
+ return 1;
+ }
+ }
+ public static class A13 {
+ public byte toByte() {
+ return 1;
+ }
+ }
+ public static class A14 {
+ public Integer toInteger() throws SerializeException {
+ throw new SerializeException("foo");
+ }
+ }
+ public static class A15 {
+ public Integer toInteger() {
+ throw new RuntimeException("foo");
+ }
+ }
+
+ @Test
+ public void a01_swap_toNumber() throws Exception {
+ assertObjectEquals("1", find(A01.class).swap(null, new A01()));
+ }
+
+ @Test
+ public void a02_swap_toInteger() throws Exception {
+ assertObjectEquals("1", find(A02.class).swap(null, new A02()));
+ }
+
+ @Test
+ public void a03_swap_toIntPrimitive() throws Exception {
+ assertObjectEquals("1", find(A03.class).swap(null, new A03()));
+ }
+
+ @Test
+ public void a04_swap_toLong() throws Exception {
+ assertObjectEquals("1", find(A04.class).swap(null, new A04()));
+ }
+
+ @Test
+ public void a05_swap_toLongPrimitive() throws Exception {
+ assertObjectEquals("1", find(A05.class).swap(null, new A05()));
+ }
+
+ @Test
+ public void a06_swap_toFloat() throws Exception {
+ assertObjectEquals("1.0", find(A06.class).swap(null, new A06()));
+ }
+
+ @Test
+ public void a07_swap_toFloatPrimitive() throws Exception {
+ assertObjectEquals("1.0", find(A07.class).swap(null, new A07()));
+ }
+
+ @Test
+ public void a08_swap_toDouble() throws Exception {
+ assertObjectEquals("1.0", find(A08.class).swap(null, new A08()));
+ }
+
+ @Test
+ public void a09_swap_toDoublePrimitive() throws Exception {
+ assertObjectEquals("1.0", find(A09.class).swap(null, new A09()));
+ }
+
+ @Test
+ public void a10_swap_toShort() throws Exception {
+ assertObjectEquals("1", find(A10.class).swap(null, new A10()));
+ }
+
+ @Test
+ public void a11_swap_toShortPrimitive() throws Exception {
+ assertObjectEquals("1", find(A11.class).swap(null, new A11()));
+ }
+
+ @Test
+ public void a12_swap_toByte() throws Exception {
+ assertObjectEquals("1", find(A12.class).swap(null, new A12()));
+ }
+
+ @Test
+ public void a13_swap_toBytePrimitive() throws Exception {
+ assertObjectEquals("1", find(A13.class).swap(null, new A13()));
+ }
+
+ @Test(expected = SerializeException.class)
+ public void a14_swap_serializeException() throws Exception {
+ find(A14.class).swap(null, null);
+ }
+
+ @Test(expected = SerializeException.class)
+ public void a15_swap_runtimeException() throws Exception {
+ find(A15.class).swap(null, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Unswap methods
+ //------------------------------------------------------------------------------------------------------------------
+// UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("fromInteger", "fromInt", "fromLong", "fromFloat", "fromDouble", "fromShort", "fromByte", "create", "valueOf");
+
+ public static class B01 {
+ public Integer toInteger() {
+ return 1;
+ }
+ public static B01 fromInteger(Integer o) {
+ assertObjectEquals("1", o);
+ return new B01();
+ }
+ }
+ public static class B02 {
+ public int toInt() {
+ return 1;
+ }
+ public static B02 fromInt(int o) {
+ assertObjectEquals("1", o);
+ return new B02();
+ }
+ }
+ public static class B03 {
+ public Long toLong() {
+ return 1l;
+ }
+ public static B03 fromLong(Long o) {
+ assertObjectEquals("1", o);
+ return new B03();
+ }
+ }
+ public static class B04 {
+ public long toLong() {
+ return 1;
+ }
+ public static B04 fromLong(long o) {
+ assertObjectEquals("1", o);
+ return new B04();
+ }
+ }
+ public static class B05 {
+ public Float toFloat() {
+ return 1f;
+ }
+ public static B05 fromFloat(Float o) {
+ assertObjectEquals("1.0", o);
+ return new B05();
+ }
+ }
+ public static class B06 {
+ public float toFloat() {
+ return 1;
+ }
+ public static B06 fromFloat(float o) {
+ assertObjectEquals("1.0", o);
+ return new B06();
+ }
+ }
+ public static class B07 {
+ public Double toDouble() {
+ return 1d;
+ }
+ public static B07 fromDouble(Double o) {
+ assertObjectEquals("1.0", o);
+ return new B07();
+ }
+ }
+ public static class B08 {
+ public double toDouble() {
+ return 1d;
+ }
+ public static B08 fromDouble(double o) {
+ assertObjectEquals("1.0", o);
+ return new B08();
+ }
+ }
+ public static class B09 {
+ public Short toShort() {
+ return 1;
+ }
+ public static B09 fromShort(Short o) {
+ assertObjectEquals("1", o);
+ return new B09();
+ }
+ }
+ public static class B10 {
+ public short toShort() {
+ return 1;
+ }
+ public static B10 fromShort(short o) {
+ assertObjectEquals("1", o);
+ return new B10();
+ }
+ }
+ public static class B11 {
+ public Byte toByte() {
+ return 1;
+ }
+ public static B11 fromByte(Byte o) {
+ assertObjectEquals("1", o);
+ return new B11();
+ }
+ }
+ public static class B12 {
+ public byte toByte() {
+ return 1;
+ }
+ public static B12 fromByte(byte o) {
+ assertObjectEquals("1", o);
+ return new B12();
+ }
+ }
+ public static class B13 {
+ public int toInt() {
+ return 1;
+ }
+ public static B13 create(int o) {
+ assertObjectEquals("1", o);
+ return new B13();
+ }
+ }
+ public static class B14 {
+ public int toInt() {
+ return 1;
+ }
+ public static B14 valueOf(int o) {
+ assertObjectEquals("1", o);
+ return new B14();
+ }
+ }
+ public static class B15 {
+ public int toInt() {
+ return 1;
+ }
+ }
+
+ @Test
+ public void b01_unswap_fromInteger() throws Exception {
+ assertNotNull(find(B01.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b02_unswap_fromInt() throws Exception {
+ assertNotNull(find(B02.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b03_unswap_fromLong() throws Exception {
+ assertNotNull(find(B03.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b04_unswap_fromLongPrimitive() throws Exception {
+ assertNotNull(find(B04.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b05_unswap_fromFloat() throws Exception {
+ assertNotNull(find(B05.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b06_unswap_fromFloatPrimitive() throws Exception {
+ assertNotNull(find(B06.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b07_unswap_fromDouble() throws Exception {
+ assertNotNull(find(B07.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b08_unswap_fromDoublePrimitive() throws Exception {
+ assertNotNull(find(B08.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b09_unswap_fromShort() throws Exception {
+ assertNotNull(find(B09.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b10_unswap_fromShortPrimitive() throws Exception {
+ assertNotNull(find(B10.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b11_unswap_fromByte() throws Exception {
+ assertNotNull(find(B11.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b12_unswap_fromBytePrimitive() throws Exception {
+ assertNotNull(find(B12.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b13_unswap_create() throws Exception {
+ assertNotNull(find(B13.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void b14_unswap_valueOf() throws Exception {
+ assertNotNull(find(B14.class).unswap(null, 1, null));
+ }
+
+ @Test(expected = ParseException.class)
+ public void b15_unswap_noMethod() throws Exception {
+ find(B15.class).unswap(null, 1, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Unswap constructor
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class C01 {
+ public C01() {}
+ public C01(Integer o) {
+ assertObjectEquals("1", o);
+ }
+ public Integer toInteger() {
+ return 1;
+ }
+ }
+ public static class C02 {
+ public C02() {}
+ public C02(int o) {
+ assertObjectEquals("1", o);
+ }
+ public int toInt() {
+ return 1;
+ }
+ }
+ public static class C03 {
+ public C03() {}
+ public C03(Long o) {
+ assertObjectEquals("1", o);
+ }
+ public Long toLong() {
+ return 1l;
+ }
+ }
+ public static class C04 {
+ public C04() {}
+ public C04(long o) {
+ assertObjectEquals("1", o);
+ }
+ public long toLong() {
+ return 1l;
+ }
+ }
+ public static class C05 {
+ public C05() {}
+ public C05(Float o) {
+ assertObjectEquals("1.0", o);
+ }
+ public Float toFloat() {
+ return 1f;
+ }
+ }
+ public static class C06 {
+ public C06() {}
+ public C06(float o) {
+ assertObjectEquals("1.0", o);
+ }
+ public float toFloat() {
+ return 1f;
+ }
+ }
+ public static class C07 {
+ public C07() {}
+ public C07(Double o) {
+ assertObjectEquals("1.0", o);
+ }
+ public Double toDouble() {
+ return 1d;
+ }
+ }
+ public static class C08 {
+ public C08() {}
+ public C08(double o) {
+ assertObjectEquals("1.0", o);
+ }
+ public double toDouble() {
+ return 1d;
+ }
+ }
+ public static class C09 {
+ public C09() {}
+ public C09(Short o) {
+ assertObjectEquals("1", o);
+ }
+ public Short toShort() {
+ return 1;
+ }
+ }
+ public static class C10 {
+ public C10() {}
+ public C10(short o) {
+ assertObjectEquals("1", o);
+ }
+ public short toShort() {
+ return 1;
+ }
+ }
+ public static class C11 {
+ public C11() {}
+ public C11(Byte o) {
+ assertObjectEquals("1", o);
+ }
+ public Byte toByte() {
+ return 1;
+ }
+ }
+ public static class C12 {
+ public C12() {}
+ public C12(byte o) {
+ assertObjectEquals("1", o);
+ }
+ public byte toByte() {
+ return 1;
+ }
+ }
+ public static class C13 {
+ public C13() {}
+ public Integer toInteger() {
+ return 1;
+ }
+ }
+
+ @Test
+ public void c01_unswapConstructor_Integer() throws Exception {
+ assertNotNull(find(C01.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void c02_unswapConstructor_int() throws Exception {
+ assertNotNull(find(C02.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void c03_unswapConstructor_Long() throws Exception {
+ assertNotNull(find(C03.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void c04_unswapConstructor_long() throws Exception {
+ assertNotNull(find(C04.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void c05_unswapConstructor_Float() throws Exception {
+ assertNotNull(find(C05.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void c06_unswapConstructor_float() throws Exception {
+ assertNotNull(find(C06.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void c07_unswapConstructor_Double() throws Exception {
+ assertNotNull(find(C07.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void c08_unswapConstructor_double() throws Exception {
+ assertNotNull(find(C08.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void c09_unswapConstructor_Short() throws Exception {
+ assertNotNull(find(C09.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void c10_unswapConstructor_short() throws Exception {
+ assertNotNull(find(C10.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void c11_unswapConstructor_Byte() throws Exception {
+ assertNotNull(find(C11.class).unswap(null, 1, null));
+ }
+
+ @Test
+ public void c12_unswapConstructor_byte() throws Exception {
+ assertNotNull(find(C12.class).unswap(null, 1, null));
+ }
+
+ @Test(expected = ParseException.class)
+ public void c13_unswapConstructor_noConstructor() throws Exception {
+ find(C13.class).unswap(null, 1, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore class
+ //------------------------------------------------------------------------------------------------------------------
+
+ @BeanIgnore
+ public static class D01 {
+ public Integer toInteger() {
+ return 1;
+ }
+ }
+ public static class D02 {
+ public class D02A {
+ public Integer toInteger() {
+ return 1;
+ }
+ }
+ }
+
+ @Test
+ public void d01_ignoreClass_beanIgnore() throws Exception {
+ assertNull(find(D01.class));
+ }
+
+ @Test
+ public void d02_ignoreClass_memberClass() throws Exception {
+ assertNull(find(D02.D02A.class));
+ }
+
+ @Test
+ public void d03_ignoreClass_numberSubclass() throws Exception {
+ assertNull(find(Integer.class));
+ assertNull(find(Number.class));
+ assertNull(find(int.class));
+ }
+
+ @Test
+ public void d04_ignoreClass_primitive() throws Exception {
+ assertNull(find(char.class));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore swap method
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class E01 {
+ @BeanIgnore
+ public Integer toInteger() {
+ return 1;
+ }
+ }
+ public static class E02 {
+ @Deprecated
+ public Integer toInteger() {
+ return 1;
+ }
+ }
+ public static class E03 {
+ public Object toInteger() {
+ return 1;
+ }
+ }
+ public static class E04 {
+ public Integer toInteger(List<String> foo) {
+ return 1;
+ }
+ }
+ public static class E05 {
+ public static Integer toInteger() {
+ return 1;
+ }
+ }
+
+ @Test
+ public void e01_ignoreSwapMethod_beanIgnore() throws Exception {
+ assertNull(find(E01.class));
+ }
+
+ @Test
+ public void e02_ignoreSwapMethod_deprecated() throws Exception {
+ assertNull(find(E02.class));
+ }
+
+ @Test
+ public void e03_ignoreSwapMethod_wrongReturnType() throws Exception {
+ assertNull(find(E03.class));
+ }
+
+ @Test
+ public void e04_ignoreSwapMethod_wrongParameters() throws Exception {
+ assertNull(find(E04.class));
+ }
+
+ @Test
+ public void e05_ignoreSwapMethod_notStatic() throws Exception {
+ assertNull(find(E05.class));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore unswap method
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class F01 {
+ public Integer toInteger() {
+ return 1;
+ }
+ @BeanIgnore
+ public static F01 create(Integer o) {
+ return null;
+ }
+ }
+ public static class F02 {
+ public Integer toInteger() {
+ return 1;
+ }
+ @Deprecated
+ public static F02 create(Integer o) {
+ return null;
+ }
+ }
+ public static class F03 {
+ public Integer toInteger() {
+ return 1;
+ }
+ public static Object create(Integer o) {
+ return null;
+ }
+ }
+ public static class F04 {
+ public Integer toInteger() {
+ return 1;
+ }
+ public static F04 create(Map<String,String> o) {
+ return null;
+ }
+ }
+ public static class F05 {
+ public Integer toInteger() {
+ return 1;
+ }
+ public F05 create(Integer o) {
+ return null;
+ }
+ }
+ public static class F06 {
+ public Integer toInteger() {
+ return 1;
+ }
+ public static F06 createx(Integer o) {
+ return null;
+ }
+ }
+
+ @Test(expected = ParseException.class)
+ public void f01_ignoreUnswapMethod_beanIgnore() throws Exception {
+ find(F01.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f02_ignoreUnswapMethod_deprecated() throws Exception {
+ find(F02.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f03_ignoreUnswapMethod_wrongReturnType() throws Exception {
+ find(F03.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f04_ignoreUnswapMethod_wrongParameters() throws Exception {
+ find(F04.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f05_ignoreUnswapMethod_notStatic() throws Exception {
+ find(F05.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f06_ignoreUnswapMethod_wrongName() throws Exception {
+ find(F06.class).unswap(null, null, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore constructor
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class G01 {
+ @BeanIgnore
+ public G01(Integer o) {}
+ public Integer toInteger() {
+ return 1;
+ }
+ }
+
+ public static class G02 {
+ @Deprecated
+ public G02(Integer o) {}
+ public Integer toInteger() {
+ return 1;
+ }
+ }
+
+ @Test(expected = ParseException.class)
+ public void g01_ignoreUnswapConstructor_beanIgnore() throws Exception {
+ find(G01.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
+ find(G02.class).unswap(null, null, null);
+ }
+}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoObjectSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoObjectSwapTest.java
new file mode 100644
index 0000000..a0eda02
--- /dev/null
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoObjectSwapTest.java
@@ -0,0 +1,353 @@
+// ***************************************************************************************************************************
+// * 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.juneau.transform;
+
+import static org.apache.juneau.testutils.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@SuppressWarnings({"unchecked","rawtypes"})
+public class AutoObjectSwapTest {
+
+
+ private static final Map<String,String> STRINGMAP = AMap.<String,String>create().append("foo","bar");
+ private static final ObjectMap OBJECTMAP = new ObjectMap().append("foo","bar");
+
+ private static PojoSwap find(Class<?> c) {
+ return AutoObjectSwap.find(ClassInfo.of(c));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Swap methods
+ //------------------------------------------------------------------------------------------------------------------
+ //SWAP_METHOD_NAMES = newUnmodifiableHashSet("swap", "toObject"),
+
+ public static class A01 {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
+ public static class A02 {
+ public ObjectMap toObject() {
+ return OBJECTMAP;
+ }
+ }
+ public static class A03 {
+ public ObjectMap toObject() throws SerializeException {
+ throw new SerializeException("foo");
+ }
+ }
+ public static class A04 {
+ public ObjectMap toObject() {
+ throw new RuntimeException("foo");
+ }
+ }
+
+ @Test
+ public void a01_swap_swap() throws Exception {
+ assertObjectEquals("{foo:'bar'}", find(A01.class).swap(null, new A01()));
+ }
+
+ @Test
+ public void a02_swap_toObject() throws Exception {
+ assertObjectEquals("{foo:'bar'}", find(A02.class).swap(null, new A02()));
+ }
+
+ @Test(expected = SerializeException.class)
+ public void a03_swap_serializeException() throws Exception {
+ find(A03.class).swap(null, null);
+ }
+
+ @Test(expected = SerializeException.class)
+ public void a04_swap_runtimeException() throws Exception {
+ find(A04.class).swap(null, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Unswap methods
+ //------------------------------------------------------------------------------------------------------------------
+ //UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("unswap", "create", "fromObject");
+
+ public static class B01 {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ public static B01 unswap(Map<String,String> o) {
+ assertObjectEquals("{foo:'bar'}", o);
+ return new B01();
+ }
+ }
+ public static class B02 {
+ public ObjectMap swap() {
+ return OBJECTMAP;
+ }
+ public static B02 create(ObjectMap o) {
+ assertObjectEquals("{foo:'bar'}", o);
+ return new B02();
+ }
+ }
+ public static class B03 {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ public static B03 fromObject(Map<String,String> o) {
+ assertObjectEquals("{foo:'bar'}", o);
+ return new B03();
+ }
+ }
+ public static class B04 {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
+
+ @Test
+ public void b01_unswap_unswap() throws Exception {
+ assertNotNull(find(B01.class).unswap(null, STRINGMAP, null));
+ }
+
+ @Test
+ public void b02_unswap_create() throws Exception {
+ assertNotNull(find(B02.class).unswap(null, OBJECTMAP, null));
+ }
+
+ @Test
+ public void b03_unswap_fromObject() throws Exception {
+ assertNotNull(find(B03.class).unswap(null, STRINGMAP, null));
+ }
+
+ @Test(expected = ParseException.class)
+ public void b04_unswap_noMethod() throws Exception {
+ find(B04.class).unswap(null, STRINGMAP, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Unswap constructor
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class C01 {
+ public C01() {}
+ public C01(Map<String,String> o) {
+ assertObjectEquals("{foo:'bar'}", o);
+ }
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
+
+ @Test
+ public void c01_unswap_constructor() throws Exception {
+ assertNotNull(find(C01.class).unswap(null, STRINGMAP, null));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore class
+ //------------------------------------------------------------------------------------------------------------------
+
+ @BeanIgnore
+ public static class D01 {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
+ public static class D02 {
+ public class D02A {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
+ }
+
+ @Test
+ public void d01_ignoreClass_beanIgnore() throws Exception {
+ assertNull(find(D01.class));
+ }
+
+ @Test
+ public void d02_ignoreClass_memberClass() throws Exception {
+ assertNull(find(D02.D02A.class));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore swap method
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class E01 {
+ @BeanIgnore
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
+ public static class E02 {
+ @Deprecated
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
+ public static class E04 {
+ public Map<String,String> swap(Map<String,String> foo) {
+ return STRINGMAP;
+ }
+ }
+ public static class E05 {
+ public static Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
+
+ @Test
+ public void e01_ignoreSwapMethod_beanIgnore() throws Exception {
+ assertNull(find(E01.class));
+ }
+
+ @Test
+ public void e02_ignoreSwapMethod_deprecated() throws Exception {
+ assertNull(find(E02.class));
+ }
+
+ @Test
+ public void e04_ignoreSwapMethod_wrongParameters() throws Exception {
+ assertNull(find(E04.class));
+ }
+
+ @Test
+ public void e05_ignoreSwapMethod_notStatic() throws Exception {
+ assertNull(find(E05.class));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore unswap method
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class F01 {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ @BeanIgnore
+ public static F01 create(Map<String,String> o) {
+ return null;
+ }
+ }
+ public static class F02 {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ @Deprecated
+ public static F02 create(Map<String,String> o) {
+ return null;
+ }
+ }
+ public static class F03 {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ public static Object create(Map<String,String> o) {
+ return null;
+ }
+ }
+ public static class F04 {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ public static F04 create(List<String> o) {
+ return null;
+ }
+ }
+ public static class F05 {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ public F05 create(Map<String,String> o) {
+ return null;
+ }
+ }
+ public static class F06 {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ public static F06 createx(Map<String,String> o) {
+ return null;
+ }
+ }
+
+ @Test(expected = ParseException.class)
+ public void f01_ignoreUnswapMethod_beanIgnore() throws Exception {
+ find(F01.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f02_ignoreUnswapMethod_deprecated() throws Exception {
+ find(F02.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f03_ignoreUnswapMethod_wrongReturnType() throws Exception {
+ find(F03.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f04_ignoreUnswapMethod_wrongParameters() throws Exception {
+ find(F04.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f05_ignoreUnswapMethod_notStatic() throws Exception {
+ find(F05.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void f06_ignoreUnswapMethod_wrongName() throws Exception {
+ find(F06.class).unswap(null, null, null);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore constructor
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class G01 {
+ @BeanIgnore
+ public G01(Map<String,String> o) {}
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
+
+ public static class G02 {
+ @Deprecated
+ public G02(Map<String,String> o) {}
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
+
+ @Test(expected = ParseException.class)
+ public void g01_ignoreUnswapConstructor_beanIgnore() throws Exception {
+ find(G01.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
+ find(G02.class).unswap(null, null, null);
+ }
+}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoStringSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoStringSwapTest.java
new file mode 100644
index 0000000..87e2e73
--- /dev/null
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoStringSwapTest.java
@@ -0,0 +1,271 @@
+// ***************************************************************************************************************************
+// * 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.juneau.transform;
+
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@SuppressWarnings({"unchecked","rawtypes"})
+public class AutoStringSwapTest {
+
+ private static PojoSwap find(Class<?> c) {
+ return AutoStringSwap.find(ClassInfo.of(c));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Unswap methods
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class B01 {
+ public static B01 fromString(String o) {
+ assertEquals("foo", o);
+ return new B01();
+ }
+ }
+ public static class B02 {
+ public static B02 fromValue(String o) {
+ assertEquals("foo", o);
+ return new B02();
+ }
+ }
+ public static class B03 {
+ public static B03 valueOf(String o) {
+ assertEquals("foo", o);
+ return new B03();
+ }
+ }
+ public static class B04 {
+ public static B04 parse(String o) {
+ assertEquals("foo", o);
+ return new B04();
+ }
+ }
+ public static class B05 {
+ public static B05 parseString(String o) {
+ assertEquals("foo", o);
+ return new B05();
+ }
+ }
+ public static class B06 {
+ public static B06 forName(String o) {
+ assertEquals("foo", o);
+ return new B06();
+ }
+ }
+ public static class B07 {
+ public static B07 forString(String o) {
+ assertEquals("foo", o);
+ return new B07();
+ }
+ }
+
+ @Test
+ public void b01_unswap_fromString() throws Exception {
+ assertNotNull(find(B01.class).unswap(null, "foo", null));
+ }
+
+ @Test
+ public void b02_unswap_fromValue() throws Exception {
+ assertNotNull(find(B02.class).unswap(null, "foo", null));
+ }
+
+ @Test
+ public void b03_unswap_valueOf() throws Exception {
+ assertNotNull(find(B03.class).unswap(null, "foo", null));
+ }
+
+ @Test
+ public void b04_unswap_parse() throws Exception {
+ assertNotNull(find(B04.class).unswap(null, "foo", null));
+ }
+
+ @Test
+ public void b05_unswap_parseString() throws Exception {
+ assertNotNull(find(B05.class).unswap(null, "foo", null));
+ }
+
+ @Test
+ public void b06_unswap_forName() throws Exception {
+ assertNotNull(find(B06.class).unswap(null, "foo", null));
+ }
+
+ @Test
+ public void b07_unswap_forString() throws Exception {
+ assertNotNull(find(B07.class).unswap(null, "foo", null));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Unswap constructor
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class C01 {
+ public C01() {}
+ public C01(String o) {
+ assertEquals("foo", o);
+ }
+ }
+ public static class C02 {
+ public C02() {}
+ public C02(String o) {
+ throw new RuntimeException("foo");
+ }
+ }
+ public static class C03 {
+ public C03() {}
+ public C03(String o) throws ParseException {
+ throw new ParseException("foo");
+ }
+ }
+
+ @Test
+ public void c01_unswapConstructor() throws Exception {
+ assertNotNull(find(C01.class).unswap(null, "foo", null));
+ }
+
+ @Test(expected = ParseException.class)
+ public void c02_unswapConstructor_runtimeException() throws Exception {
+ assertNotNull(find(C02.class).unswap(null, "foo", null));
+ }
+
+ @Test(expected = ParseException.class)
+ public void c03_unswapConstructor_parseException() throws Exception {
+ assertNotNull(find(C03.class).unswap(null, "foo", null));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore class
+ //------------------------------------------------------------------------------------------------------------------
+
+ @BeanIgnore
+ public static class D01 {
+ public static D01 fromString(String s) {
+ return new D01();
+ }
+ }
+ public static class D02 {
+ public class D02A {
+ public D02A fromString(String s) {
+ return new D02A();
+ }
+ }
+ }
+
+ @Test
+ public void d01_ignoreClass_beanIgnore() throws Exception {
+ assertNull(find(D01.class));
+ }
+
+ @Test
+ public void d02_ignoreClass_memberClass() throws Exception {
+ assertNull(find(D02.D02A.class));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore unswap method
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class F01 {
+ @BeanIgnore
+ public static F01 fromString(String o) {
+ return null;
+ }
+ }
+ public static class F02 {
+ @Deprecated
+ public static F02 fromString(String o) {
+ return null;
+ }
+ }
+ public static class F03 {
+ public static Object fromString(String o) {
+ return null;
+ }
+ }
+ public static class F04 {
+ public static F04 fromString(Map<String,String> o) {
+ return null;
+ }
+ }
+ public static class F05 {
+ public F05 fromString(String o) {
+ return null;
+ }
+ }
+ public static class F06 {
+ public static F06 createx(String o) {
+ return null;
+ }
+ }
+
+ @Test
+ public void f01_ignoreUnswapMethod_beanIgnore() throws Exception {
+ assertNull(find(F01.class));
+ }
+
+ @Test
+ public void f02_ignoreUnswapMethod_deprecated() throws Exception {
+ assertNull(find(F02.class));
+ }
+
+ @Test
+ public void f03_ignoreUnswapMethod_wrongReturnType() throws Exception {
+ assertNull(find(F03.class));
+ }
+
+ @Test
+ public void f04_ignoreUnswapMethod_wrongParameters() throws Exception {
+ assertNull(find(F04.class));
+ }
+
+ @Test
+ public void f05_ignoreUnswapMethod_notStatic() throws Exception {
+ assertNull(find(F05.class));
+ }
+
+ @Test
+ public void f06_ignoreUnswapMethod_wrongName() throws Exception {
+ assertNull(find(F06.class));
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Ignore constructor
+ //------------------------------------------------------------------------------------------------------------------
+
+ public static class G01 {
+ @BeanIgnore
+ public G01(String o) {}
+ }
+
+ public static class G02 {
+ @Deprecated
+ public G02(String o) {}
+ }
+
+ @Test
+ public void g01_ignoreUnswapConstructor_beanIgnore() throws Exception {
+ assertNull(find(G01.class));
+ }
+
+ @Test
+ public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
+ assertNull(find(G02.class));
+ }
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
index e2e5157..bd8d1b3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
@@ -48,7 +48,7 @@ public class BeanProxyInvocationHandler<T> implements InvocationHandler {
@Override /* InvocationHandler */
public Object invoke(Object proxy, Method method, Object[] args) {
MethodInfo mi = MethodInfo.of(method);
- if (mi.hasName("equals") && mi.hasArgs(java.lang.Object.class)) {
+ if (mi.hasName("equals") && mi.hasParamTypes(java.lang.Object.class)) {
Object arg = args[0];
if (arg == null)
return false;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index 88be006..de10c27 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -441,7 +441,7 @@ public final class ClassMeta<T> implements Type {
for (String methodName : new String[]{"fromString","fromValue","valueOf","parse","parseString","forName","forString"}) {
if (fromStringMethod == null) {
for (MethodInfo m : ci.getPublicMethods()) {
- if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasName(methodName) && m.hasReturnType(c) && m.hasArgs(String.class)) {
+ if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasName(methodName) && m.hasReturnType(c) && m.hasParamTypes(String.class)) {
fromStringMethod = m.inner();
break;
}
@@ -451,7 +451,7 @@ public final class ClassMeta<T> implements Type {
// Find example() method if present.
for (MethodInfo m : ci.getPublicMethods()) {
- if (m.isAll(PUBLIC, NOT_DEPRECATED, STATIC) && m.hasName("example") && m.hasFuzzyArgs(BeanSession.class)) {
+ if (m.isAll(PUBLIC, NOT_DEPRECATED, STATIC) && m.hasName("example") && m.hasFuzzyParamTypes(BeanSession.class)) {
exampleMethod = m.inner();
break;
}
@@ -499,7 +499,7 @@ public final class ClassMeta<T> implements Type {
for (MethodInfo m : ci.getDeclaredMethods()) {
if (m.hasAnnotation(Example.class)) {
- if (! (m.isStatic() && m.hasFuzzyArgs(BeanSession.class) && ci.isParentOf(m.getReturnType().inner())))
+ if (! (m.isStatic() && m.hasFuzzyParamTypes(BeanSession.class) && ci.isParentOf(m.getReturnType().inner())))
throw new ClassMetaRuntimeException("@Example used on invalid method ''{0}''. Must be static and return an instance of the declaring class.", m);
m.setAccessible();
exampleMethod = m.inner();
@@ -702,7 +702,16 @@ public final class ClassMeta<T> implements Type {
PojoSwap defaultSwap = DefaultSwaps.find(ci);
if (defaultSwap == null)
- defaultSwap = DynamicSwaps.find(ci);
+ defaultSwap = AutoObjectSwap.find(ci);
+ if (defaultSwap == null)
+ defaultSwap = AutoNumberSwap.find(ci);
+ if (defaultSwap == null)
+ defaultSwap = AutoMapSwap.find(ci);
+ if (defaultSwap == null)
+ defaultSwap = AutoListSwap.find(ci);
+ // TODO
+ //if (defaultSwap == null)
+ // defaultSwap = AutoStringSwap.find(ci);
if (defaultSwap != null)
l.add(defaultSwap);
}
@@ -1545,7 +1554,7 @@ public final class ClassMeta<T> implements Type {
*/
public boolean canCreateNewInstance(Object outer) {
if (isMemberClass)
- return outer != null && noArgConstructor != null && noArgConstructor.hasArgs(outer.getClass());
+ return outer != null && noArgConstructor != null && noArgConstructor.hasParamTypes(outer.getClass());
return canCreateNewInstance();
}
@@ -1565,7 +1574,7 @@ public final class ClassMeta<T> implements Type {
if (beanMeta.constructor == null)
return false;
if (isMemberClass)
- return outer != null && beanMeta.constructor.hasArgs(outer.getClass());
+ return outer != null && beanMeta.constructor.hasParamTypes(outer.getClass());
return true;
}
@@ -1582,7 +1591,7 @@ public final class ClassMeta<T> implements Type {
return true;
if (stringConstructor != null) {
if (isMemberClass)
- return outer != null && stringConstructor.hasArgs(outer.getClass(), String.class);
+ return outer != null && stringConstructor.hasParamTypes(outer.getClass(), String.class);
return true;
}
return false;
@@ -1599,7 +1608,7 @@ public final class ClassMeta<T> implements Type {
public boolean canCreateNewInstanceFromNumber(Object outer) {
if (numberConstructor != null) {
if (isMemberClass)
- return outer != null && numberConstructor.hasArgs(outer.getClass());
+ return outer != null && numberConstructor.hasParamTypes(outer.getClass());
return true;
}
return false;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java
index e90583a..e9a2b7d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java
@@ -37,7 +37,7 @@ import java.lang.annotation.*;
* </ul>
*/
@Documented
-@Target({FIELD,METHOD,TYPE})
+@Target({FIELD,METHOD,TYPE,CONSTRUCTOR})
@Retention(RUNTIME)
@Inherited
public @interface BeanIgnore {}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
index 083dab1..4c69fb4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
@@ -56,8 +56,8 @@ public final class ClassUtils {
/**
* Shortcut for calling {@link MethodInfo#of(ClassInfo, Method)}.
- *
- * @param c
+ *
+ * @param c
* The class containing the method.
* <br>Note that this isn't necessarily the declaring class, but could be a subclass
* of the declaring class.
@@ -165,6 +165,29 @@ public final class ClassUtils {
* @param argTypes The class types of the arguments being passed to the method.
* @return The number of matching arguments, or <c>-1</c> a parameter was found that isn't in the list of args.
*/
+ public static int fuzzyArgsMatch(Class<?>[] paramTypes, ClassInfo... argTypes) {
+ int matches = 0;
+ outer: for (Class<?> p : paramTypes) {
+ ClassInfo pi = getClassInfo(p).getWrapperInfoIfPrimitive();
+ for (ClassInfo a : argTypes) {
+ ClassInfo ai = a.getWrapperInfoIfPrimitive();
+ if (pi.isParentOf(ai.inner())) {
+ matches++;
+ continue outer;
+ }
+ }
+ return -1;
+ }
+ return matches;
+ }
+
+ /**
+ * Returns a number representing the number of arguments that match the specified parameters.
+ *
+ * @param paramTypes The parameters types specified on a method.
+ * @param argTypes The class types of the arguments being passed to the method.
+ * @return The number of matching arguments, or <c>-1</c> a parameter was found that isn't in the list of args.
+ */
public static int fuzzyArgsMatch(List<ClassInfo> paramTypes, Class<?>... argTypes) {
int matches = 0;
outer: for (ClassInfo p : paramTypes) {
@@ -313,7 +336,7 @@ public final class ClassUtils {
for (int i = 0; i < paramTypes.length; i++) {
ClassInfo pt = getClassInfo(paramTypes[i]).getWrapperInfoIfPrimitive();
for (int j = 0; j < args.length; j++) {
- if (pt.isParentOf(args[j].getClass())) {
+ if (args[j] != null && pt.isParentOf(args[j].getClass())) {
params[i] = args[j];
break;
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
index 96538d7..9e102ae 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
@@ -474,4 +474,15 @@ public final class CollectionUtils {
m.put(key, value);
return m;
}
+
+ /**
+ * Converts the specified arguments into an unmodifiable {@link HashSet}.
+ *
+ * @param values The entries to populate the hashset with.
+ * @return A new {@link HashSet} populated with the specified arguments.
+ */
+ @SafeVarargs
+ public static <T> Set<T> newUnmodifiableHashSet(T...values) {
+ return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(values)));
+ }
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParseException.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParseException.java
index d8e0c8c..4087f8a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParseException.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParseException.java
@@ -14,11 +14,13 @@ package org.apache.juneau.parser;
import static org.apache.juneau.internal.StringUtils.*;
+import java.lang.reflect.*;
import java.text.*;
import java.util.*;
import org.apache.juneau.*;
import org.apache.juneau.internal.*;
+import org.apache.juneau.serializer.*;
/**
* Exception that indicates invalid syntax encountered during parsing.
@@ -28,6 +30,25 @@ public class ParseException extends FormattedException {
private static final long serialVersionUID = 1L;
/**
+ * Creator method.
+ *
+ * <p>
+ * If the throwable is already a {@link ParseException}, we simply return that exception as-is.
+ * If the throwable is an {@link InvocationTargetException}, we unwrap the thrown exception.
+ * Otherwise we create a new {@link ParseException}.
+ *
+ * @param e The exception being wrapped or unwrapped.
+ * @return A new {@link SerializeException}.
+ */
+ public static ParseException create(Throwable e) {
+ if (e instanceof InvocationTargetException)
+ e = ((InvocationTargetException)e).getCause();
+ if (e instanceof ParseException)
+ return (ParseException)e;
+ return new ParseException(e);
+ }
+
+ /**
* Constructor.
*
* @param message The {@link MessageFormat}-style message.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
index 1610486..6ab9fee 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
@@ -325,7 +325,7 @@ public final class ClassInfo {
*/
public MethodInfo getPublicMethod(String name, Class<?>...args) {
for (MethodInfo mi : getPublicMethods())
- if (mi.hasName(name) && mi.hasArgs(args))
+ if (mi.hasName(name) && mi.hasParamTypes(args))
return mi;
return null;
}
@@ -340,7 +340,7 @@ public final class ClassInfo {
*/
public MethodInfo getMethod(String name, Class<?>...args) {
for (MethodInfo mi : getAllMethods())
- if (mi.hasName(name) && mi.hasArgs(args))
+ if (mi.hasName(name) && mi.hasParamTypes(args))
return mi;
return null;
}
@@ -431,7 +431,7 @@ public final class ClassInfo {
for (MethodInfo m : getPublicMethods())
if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED)
&& m.hasReturnType(c)
- && m.hasArgs(String.class)
+ && m.hasParamTypes(String.class)
&& isOneOf(m.getSimpleName(), "create","fromString","fromValue","valueOf","parse","parseString","forName","forString"))
return m;
return null;
@@ -454,7 +454,7 @@ public final class ClassInfo {
public MethodInfo getStaticCreateMethod(Class<?> ic) {
if (c != null) {
for (MethodInfo m : getPublicMethods()) {
- if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasReturnType(c) && m.hasArgs(ic)) {
+ if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasReturnType(c) && m.hasParamTypes(ic)) {
String n = m.getSimpleName();
if (isOneOf(n, "create","from") || (n.startsWith("from") && n.substring(4).equals(ic.getSimpleName()))) {
return m;
@@ -476,7 +476,7 @@ public final class ClassInfo {
public MethodInfo getStaticPublicMethod(String name, Class<?> rt, Class<?>...args) {
if (c != null)
for (MethodInfo m : getPublicMethods())
- if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && name.equals(m.getSimpleName()) && m.hasReturnType(rt) && m.hasArgs(args))
+ if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && name.equals(m.getSimpleName()) && m.hasReturnType(rt) && m.hasParamTypes(args))
return m;
return null;
}
@@ -548,7 +548,7 @@ public final class ClassInfo {
*/
public ConstructorInfo getPublicConstructor(Class<?>...args) {
for (ConstructorInfo ci : getPublicConstructors())
- if (ci.hasArgs(args))
+ if (ci.hasParamTypes(args))
return ci;
return null;
}
@@ -562,7 +562,7 @@ public final class ClassInfo {
*/
public ConstructorInfo getDeclaredConstructor(Class<?>...args) {
for (ConstructorInfo ci : getDeclaredConstructors())
- if (ci.hasArgs(args))
+ if (ci.hasParamTypes(args))
return ci;
return null;
}
@@ -1444,6 +1444,15 @@ public final class ClassInfo {
}
/**
+ * Returns <jk>false</jk> if this class is a member class and not static.
+ *
+ * @return <jk>false</jk> if this class is a member class and not static.
+ */
+ public boolean isNotNonStaticMemberClass() {
+ return ! isNonStaticMemberClass();
+ }
+
+ /**
* Returns <jk>true</jk> if this class is a local class.
*
* @return <jk>true</jk> if this class is a local class.
@@ -1823,6 +1832,16 @@ public final class ClassInfo {
}
/**
+ * Returns <jk>true</jk> if this class is a child or the same as <c>parent</c>.
+ *
+ * @param parent The parent class.
+ * @return <jk>true</jk> if this class is a parent or the same as <c>parent</c>.
+ */
+ public boolean isChildOf(ClassInfo parent) {
+ return isChildOf(parent.inner());
+ }
+
+ /**
* Checks for equality with the specified class.
*
* @param c The class to check equality with.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
index 36373fe..df1d89c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
@@ -512,7 +512,7 @@ public abstract class ExecutableInfo {
* @param args The arguments to test for.
* @return <jk>true</jk> if this method has this arguments in the exact order.
*/
- public final boolean hasArgs(Class<?>...args) {
+ public final boolean hasParamTypes(Class<?>...args) {
Class<?>[] pt = rawParamTypes();
if (pt.length == args.length) {
for (int i = 0; i < pt.length; i++)
@@ -524,12 +524,29 @@ public abstract class ExecutableInfo {
}
/**
+ * Returns <jk>true</jk> if this method has the specified arguments.
+ *
+ * @param args The arguments to test for.
+ * @return <jk>true</jk> if this method has this arguments in the exact order.
+ */
+ public final boolean hasParamTypes(ClassInfo...args) {
+ Class<?>[] pt = rawParamTypes();
+ if (pt.length == args.length) {
+ for (int i = 0; i < pt.length; i++)
+ if (! pt[i].equals(args[i].inner()))
+ return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Returns <jk>true</jk> if this method has the specified argument parent classes.
*
* @param args The arguments to test for.
* @return <jk>true</jk> if this method has this arguments in the exact order.
*/
- public final boolean hasArgParents(Class<?>...args) {
+ public final boolean hasParamTypeParents(Class<?>...args) {
Class<?>[] pt = rawParamTypes();
if (pt.length == args.length) {
for (int i = 0; i < pt.length; i++)
@@ -541,12 +558,39 @@ public abstract class ExecutableInfo {
}
/**
+ * Returns <jk>true</jk> if this method has the specified argument parent classes.
+ *
+ * @param args The arguments to test for.
+ * @return <jk>true</jk> if this method has this arguments in the exact order.
+ */
+ public final boolean hasParamTypeParents(ClassInfo...args) {
+ Class<?>[] pt = rawParamTypes();
+ if (pt.length == args.length) {
+ for (int i = 0; i < pt.length; i++)
+ if (! args[i].inner().isAssignableFrom(pt[i]))
+ return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Returns <jk>true</jk> if this method has at most only this arguments in any order.
*
* @param args The arguments to test for.
* @return <jk>true</jk> if this method has at most only this arguments in any order.
*/
- public final boolean hasFuzzyArgs(Class<?>...args) {
+ public final boolean hasFuzzyParamTypes(Class<?>...args) {
+ return ClassUtils.fuzzyArgsMatch(rawParamTypes(), args) != -1;
+ }
+
+ /**
+ * Returns <jk>true</jk> if this method has at most only this arguments in any order.
+ *
+ * @param args The arguments to test for.
+ * @return <jk>true</jk> if this method has at most only this arguments in any order.
+ */
+ public boolean hasFuzzyParamTypes(ClassInfo...args) {
return ClassUtils.fuzzyArgsMatch(rawParamTypes(), args) != -1;
}
@@ -667,6 +711,29 @@ public abstract class ExecutableInfo {
return getSimpleName().equals(name);
}
+ /**
+ * Returns <jk>true</jk> if this method has a name in the specified list.
+ *
+ * @param names The names to test for.
+ * @return <jk>true</jk> if this method has one of the names.
+ */
+ public final boolean hasName(String...names) {
+ for (String n : names)
+ if (getSimpleName().equals(n))
+ return true;
+ return false;
+ }
+
+ /**
+ * Returns <jk>true</jk> if this method has a name in the specified set.
+ *
+ * @param names The names to test for.
+ * @return <jk>true</jk> if this method has one of the names.
+ */
+ public final boolean hasName(Set<String> names) {
+ return names.contains(getSimpleName());
+ }
+
//-----------------------------------------------------------------------------------------------------------------
// Labels
//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
index c0fb331..9f7776a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
@@ -20,7 +20,7 @@ import java.lang.reflect.*;
import java.util.*;
import java.util.function.*;
-import org.apache.juneau.ExecutableException;
+import org.apache.juneau.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.internal.*;
@@ -380,6 +380,16 @@ public final class MethodInfo extends ExecutableInfo implements Comparable<Metho
}
/**
+ * Returns <jk>true</jk> if this method has this return type.
+ *
+ * @param ci The return type to test for.
+ * @return <jk>true</jk> if this method has this return type.
+ */
+ public boolean hasReturnType(ClassInfo ci) {
+ return hasReturnType(ci.inner());
+ }
+
+ /**
* Returns <jk>true</jk> if this method has this parent return type.
*
* @param c The return type to test for.
@@ -389,6 +399,16 @@ public final class MethodInfo extends ExecutableInfo implements Comparable<Metho
return ClassInfo.of(c).isParentOf(m.getReturnType());
}
+ /**
+ * Returns <jk>true</jk> if this method has this parent return type.
+ *
+ * @param ci The return type to test for.
+ * @return <jk>true</jk> if this method has this parent return type.
+ */
+ public boolean hasReturnTypeParent(ClassInfo ci) {
+ return hasReturnTypeParent(ci.inner());
+ }
+
//-----------------------------------------------------------------------------------------------------------------
// Other methods
//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializeException.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializeException.java
index e6242fe..9050d39 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializeException.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializeException.java
@@ -14,6 +14,7 @@ package org.apache.juneau.serializer;
import static org.apache.juneau.internal.StringUtils.*;
+import java.lang.reflect.*;
import java.text.*;
import java.util.*;
@@ -28,6 +29,25 @@ public class SerializeException extends FormattedException {
private static final long serialVersionUID = 1L;
/**
+ * Creator method.
+ *
+ * <p>
+ * If the throwable is already a {@link SerializeException}, we simply return that exception as-is.
+ * If the throwable is an {@link InvocationTargetException}, we unwrap the thrown exception.
+ * Otherwise we create a new {@link SerializeException}.
+ *
+ * @param e The exception being wrapped or unwrapped.
+ * @return A new {@link SerializeException}.
+ */
+ public static SerializeException create(Throwable e) {
+ if (e instanceof InvocationTargetException)
+ e = ((InvocationTargetException)e).getCause();
+ if (e instanceof SerializeException)
+ return (SerializeException)e;
+ return new SerializeException(e);
+ }
+
+ /**
* Constructor.
*
* @param session The serializer session to extract information from.
@@ -63,7 +83,7 @@ public class SerializeException extends FormattedException {
*
* @param causedBy The inner exception.
*/
- public SerializeException(Exception causedBy) {
+ public SerializeException(Throwable causedBy) {
super(causedBy, getMessage(null, causedBy.getMessage()));
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java
new file mode 100644
index 0000000..2602c4f
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java
@@ -0,0 +1,182 @@
+// ***************************************************************************************************************************
+// * 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.juneau.transform;
+
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ClassUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * A dynamic POJO swap based on reflection of a Java class that converts POJOs to Lists.
+ *
+ * <p>
+ * Looks for methods on the class that can be called to swap-in surrogate List objects before serialization and swap-out
+ * surrogate List objects after parsing.
+ *
+ * <h5 class='figure'>Valid surrogate objects</h5>
+ * <ul>
+ * <li class='jc'>Any subclass of {@link List}
+ * </ul>
+ *
+ * <h5 class='figure'>Valid swap methods (S = Swapped type)</h5>
+ * <ul>
+ * <li class='jm'><c><jk>public</jk> S toList()</c>
+ * <li class='jm'><c><jk>public</jk> S toList(BeanSession)</c>
+ * <li class='jm'><c><jk>public</jk> S toObjectList()</c>
+ * <li class='jm'><c><jk>public</jk> S toObjectList(BeanSession)</c>
+ * </ul>
+ *
+ * <h5 class='figure'>Valid unswap methods (N = Normal type, S = Swapped type)</h5>
+ * <ul>
+ * <li class='jm'><c><jk>public static</jk> N fromList(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromList(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromObjectList(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromObjectList(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N create(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N create(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N valueOf(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N valueOf(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public</jk> N(S)</c>
+ * </ul>
+ *
+ * <p>
+ * Classes are ignored if any of the following are true:
+ * <ul>
+ * <li>Classes annotated with {@link BeanIgnore @BeanIgnore}.
+ * <li>Non-static member classes.
+ * </ul>
+ *
+ * <p>
+ * Members/constructors are ignored if any of the following are true:
+ * <ul>
+ * <li>Members/constructors annotated with {@link BeanIgnore @BeanIgnore}.
+ * <li>Deprecated members/constructors.
+ * </ul>
+ *
+ * @param <T> The normal class type.
+ */
+public class AutoListSwap<T> extends PojoSwap<T,List<?>> {
+
+ private static final Set<String>
+ SWAP_METHOD_NAMES = newUnmodifiableHashSet("toList", "toObjectList"),
+ UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("fromList", "fromObjectList", "create", "valueOf");
+
+ /**
+ * Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
+ *
+ * @param ci The class to try to constructor a dynamic swap on.
+ * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
+ */
+ @SuppressWarnings({ "rawtypes" })
+ public static PojoSwap<?,?> find(ClassInfo ci) {
+
+ if (shouldIgnore(ci))
+ return null;
+
+ // Find swap() method if present.
+ for (MethodInfo m : ci.getPublicMethods()) {
+ if (isSwapMethod(m)) {
+
+ ClassInfo rt = m.getReturnType();
+
+ for (MethodInfo m2 : ci.getPublicMethods())
+ if (isUnswapMethod(m2, ci, rt))
+ return new AutoListSwap(ci, m, m2, null);
+
+ for (ConstructorInfo cs : ci.getPublicConstructors())
+ if (isUnswapConstructor(cs, rt))
+ return new AutoListSwap(ci, m, null, cs);
+
+ return new AutoListSwap(ci, m, null, null);
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean shouldIgnore(ClassInfo ci) {
+ return
+ ci.hasAnnotation(BeanIgnore.class)
+ || ci.isNonStaticMemberClass();
+ }
+
+ private static boolean isSwapMethod(MethodInfo mi) {
+ return
+ mi.isNotDeprecated()
+ && mi.isNotStatic()
+ && mi.hasName(SWAP_METHOD_NAMES)
+ && mi.hasReturnTypeParent(List.class)
+ && mi.hasFuzzyParamTypes(BeanSession.class)
+ && ! mi.hasAnnotation(BeanIgnore.class);
+ }
+
+ private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+ return
+ mi.isNotDeprecated()
+ && mi.isStatic()
+ && mi.hasName(UNSWAP_METHOD_NAMES)
+ && mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
+ && mi.hasReturnTypeParent(ci)
+ && ! mi.hasAnnotation(BeanIgnore.class);
+ }
+
+ private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+ return
+ cs.isNotDeprecated()
+ && cs.hasParamTypeParents(rt)
+ && ! cs.hasAnnotation(BeanIgnore.class);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+
+ private final Method swapMethod, unswapMethod;
+ private final Constructor<?> unswapConstructor;
+
+ private AutoListSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+ super(ci.inner(), swapMethod.getReturnType().inner());
+ this.swapMethod = swapMethod.inner();
+ this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
+ this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+ }
+
+ @Override /* PojoSwap */
+ public List<?> swap(BeanSession session, Object o) throws SerializeException {
+ try {
+ return (List<?>)swapMethod.invoke(o, getMatchingArgs(swapMethod.getParameterTypes(), session));
+ } catch (Exception e) {
+ throw SerializeException.create(e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override /* PojoSwap */
+ public T unswap(BeanSession session, List<?> o, ClassMeta<?> hint) throws ParseException {
+ try {
+ if (unswapMethod != null)
+ return (T)unswapMethod.invoke(null, getMatchingArgs(unswapMethod.getParameterTypes(), session, o));
+ if (unswapConstructor != null)
+ return (T)unswapConstructor.newInstance(o);
+ return super.unswap(session, o, hint);
+ } catch (Exception e) {
+ throw ParseException.create(e);
+ }
+ }
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java
new file mode 100644
index 0000000..53dace1
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java
@@ -0,0 +1,182 @@
+// ***************************************************************************************************************************
+// * 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.juneau.transform;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * A dynamic POJO swap based on reflection of a Java class that converts POJOs to serializable Maps.
+ *
+ * <p>
+ * Looks for methods on the class that can be called to swap-in surrogate Map objects before serialization and swap-out
+ * surrogate Map objects after parsing.
+ *
+ * <h5 class='figure'>Valid surrogate objects</h5>
+ * <ul>
+ * <li class='jc'>Any subclass of {@link Map}
+ * </ul>
+ *
+ * <h5 class='figure'>Valid swap methods (S = Swapped type)</h5>
+ * <ul>
+ * <li class='jm'><c><jk>public</jk> S toMap()</c>
+ * <li class='jm'><c><jk>public</jk> S toMap(BeanSession)</c>
+ * <li class='jm'><c><jk>public</jk> S toObjectMap()</c>
+ * <li class='jm'><c><jk>public</jk> S toObjectMap(BeanSession)</c>
+ * </ul>
+ *
+ * <h5 class='figure'>Valid unswap methods (N = Normal type, S = Swapped type)</h5>
+ * <ul>
+ * <li class='jm'><c><jk>public static</jk> N fromMap(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromMap(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromObjectMap(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromObjectMap(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N create(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N create(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N valueOf(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N valueOf(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public</jk> N(S)</c>
+ * </ul>
+ *
+ * <p>
+ * Classes are ignored if any of the following are true:
+ * <ul>
+ * <li>Classes annotated with {@link BeanIgnore @BeanIgnore}.
+ * <li>Non-static member classes.
+ * </ul>
+ *
+ * <p>
+ * Members/constructors are ignored if any of the following are true:
+ * <ul>
+ * <li>Members/constructors annotated with {@link BeanIgnore @BeanIgnore}.
+ * <li>Deprecated members/constructors.
+ * </ul>
+ *
+ * @param <T> The normal class type.
+ */
+public class AutoMapSwap<T> extends PojoSwap<T,Map<?,?>> {
+
+ private static final Set<String>
+ SWAP_METHOD_NAMES = newUnmodifiableHashSet("toMap", "toObjectMap"),
+ UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("fromMap", "fromObjectMap", "create", "valueOf");
+
+ /**
+ * Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
+ *
+ * @param ci The class to try to constructor a dynamic swap on.
+ * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
+ */
+ @SuppressWarnings({ "rawtypes" })
+ public static PojoSwap<?,?> find(ClassInfo ci) {
+
+ if (shouldIgnore(ci))
+ return null;
+
+ // Find swap() method if present.
+ for (MethodInfo m : ci.getPublicMethods()) {
+ if (isSwapMethod(m)) {
+
+ ClassInfo rt = m.getReturnType();
+
+ for (MethodInfo m2 : ci.getPublicMethods())
+ if (isUnswapMethod(m2, ci, rt))
+ return new AutoMapSwap(ci, m, m2, null);
+
+ for (ConstructorInfo cs : ci.getPublicConstructors())
+ if (isUnswapConstructor(cs, rt))
+ return new AutoMapSwap(ci, m, null, cs);
+
+ return new AutoMapSwap(ci, m, null, null);
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean shouldIgnore(ClassInfo ci) {
+ return
+ ci.hasAnnotation(BeanIgnore.class)
+ || ci.isNonStaticMemberClass();
+ }
+
+ private static boolean isSwapMethod(MethodInfo mi) {
+ return
+ mi.isNotDeprecated()
+ && mi.isNotStatic()
+ && mi.hasName(SWAP_METHOD_NAMES)
+ && mi.hasReturnTypeParent(Map.class)
+ && mi.hasFuzzyParamTypes(BeanSession.class)
+ && ! mi.hasAnnotation(BeanIgnore.class);
+ }
+
+ private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+ return
+ mi.isNotDeprecated()
+ && mi.isStatic()
+ && mi.hasName(UNSWAP_METHOD_NAMES)
+ && mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
+ && mi.hasReturnTypeParent(ci)
+ && ! mi.hasAnnotation(BeanIgnore.class);
+ }
+
+ private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+ return
+ cs.isNotDeprecated()
+ && cs.hasParamTypeParents(rt)
+ && ! cs.hasAnnotation(BeanIgnore.class);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+
+ private final Method swapMethod, unswapMethod;
+ private final Constructor<?> unswapConstructor;
+
+ private AutoMapSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+ super(ci.inner(), swapMethod.inner().getReturnType());
+ this.swapMethod = swapMethod.inner();
+ this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
+ this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+ }
+
+ @Override /* PojoSwap */
+ public Map<?,?> swap(BeanSession session, Object o) throws SerializeException {
+ try {
+ return (Map<?,?>)swapMethod.invoke(o, getMatchingArgs(swapMethod.getParameterTypes(), session));
+ } catch (Exception e) {
+ throw SerializeException.create(e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override /* PojoSwap */
+ public T unswap(BeanSession session, Map<?,?> o, ClassMeta<?> hint) throws ParseException {
+ try {
+ if (unswapMethod != null)
+ return (T)unswapMethod.invoke(null, getMatchingArgs(unswapMethod.getParameterTypes(), session, o));
+ if (unswapConstructor != null)
+ return (T)unswapConstructor.newInstance(o);
+ return super.unswap(session, o, hint);
+ } catch (Exception e) {
+ throw ParseException.create(e);
+ }
+ }
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java
new file mode 100644
index 0000000..80ae1cc
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java
@@ -0,0 +1,222 @@
+// ***************************************************************************************************************************
+// * 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.juneau.transform;
+
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ClassUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * A dynamic POJO swap based on reflection of a Java class that converts POJOs to Number serializable objects.
+ *
+ * <p>
+ * Looks for methods on the class that can be called to swap-in surrogate Number objects before serialization and swap-out
+ * surrogate Number objects after parsing.
+ *
+ * <h5 class='figure'>Valid surrogate objects</h5>
+ * <ul>
+ * <li class='jc'>Any subclass of {@link Number}
+ * <li class='jc'>Any number primitive
+ * </ul>
+ *
+ * <h5 class='figure'>Valid swap methods (S = Swapped type)</h5>
+ * <ul>
+ * <li class='jm'><c><jk>public</jk> S toNumber()</c>
+ * <li class='jm'><c><jk>public</jk> S toNumber(BeanSession)</c>
+ * <li class='jm'><c><jk>public</jk> S toInteger()</c>
+ * <li class='jm'><c><jk>public</jk> S toInteger(BeanSession)</c>
+ * <li class='jm'><c><jk>public</jk> S toInt()</c>
+ * <li class='jm'><c><jk>public</jk> S toInt(BeanSession)</c>
+ * <li class='jm'><c><jk>public</jk> S toLong()</c>
+ * <li class='jm'><c><jk>public</jk> S toLong(BeanSession)</c>
+ * <li class='jm'><c><jk>public</jk> S toFloat()</c>
+ * <li class='jm'><c><jk>public</jk> S toFloat(BeanSession)</c>
+ * <li class='jm'><c><jk>public</jk> S toDouble()</c>
+ * <li class='jm'><c><jk>public</jk> S toDouble(BeanSession)</c>
+ * <li class='jm'><c><jk>public</jk> S toShort()</c>
+ * <li class='jm'><c><jk>public</jk> S toShort(BeanSession)</c>
+ * <li class='jm'><c><jk>public</jk> S toByte()</c>
+ * <li class='jm'><c><jk>public</jk> S toByte(BeanSession)</c>
+ * </ul>
+ *
+ * <h5 class='figure'>Valid unswap methods (N = Normal type, S = Swapped type)</h5>
+ * <ul>
+ * <li class='jm'><c><jk>public static</jk> N fromInteger(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromInteger(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromInt(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromInt(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromLong(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromLong(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromFloat(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromFloat(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromDouble(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromDouble(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromShort(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromShort(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromByte(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromByte(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N create(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N create(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N valueOf(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N valueOf(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public</jk> N(S)</c>
+ * </ul>
+ * <p>
+ * Classes are ignored if any of the following are true:
+ * <ul>
+ * <li>Classes annotated with {@link BeanIgnore @BeanIgnore}.
+ * <li>Non-static member classes.
+ * </ul>
+ *
+ * <p>
+ * Members/constructors are ignored if any of the following are true:
+ * <ul>
+ * <li>Members/constructors annotated with {@link BeanIgnore @BeanIgnore}.
+ * <li>Deprecated members/constructors.
+ * </ul>
+ *
+ * @param <T> The normal class type.
+ */
+public class AutoNumberSwap<T> extends PojoSwap<T,Number> {
+
+ private static final Set<String>
+ SWAP_METHOD_NAMES = newUnmodifiableHashSet("toNumber", "toInteger", "toInt", "toLong", "toFloat", "toDouble", "toShort", "toByte"),
+ UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("fromInteger", "fromInt", "fromLong", "fromFloat", "fromDouble", "fromShort", "fromByte", "create", "valueOf");
+
+ /**
+ * Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
+ *
+ * @param ci The class to try to constructor a dynamic swap on.
+ * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
+ */
+ @SuppressWarnings({ "rawtypes" })
+ public static PojoSwap<?,?> find(ClassInfo ci) {
+
+ if (shouldIgnore(ci))
+ return null;
+
+ // Find swap() method if present.
+ for (MethodInfo m : ci.getPublicMethods()) {
+ if (isSwapMethod(m)) {
+
+ ClassInfo rt = m.getReturnType();
+
+ for (MethodInfo m2 : ci.getPublicMethods())
+ if (isUnswapMethod(m2, ci, rt))
+ return new AutoNumberSwap(ci, m, m2, null);
+
+ for (ConstructorInfo cs : ci.getPublicConstructors())
+ if (isUnswapConstructor(cs, rt))
+ return new AutoNumberSwap(ci, m, null, cs);
+
+ return new AutoNumberSwap(ci, m, null, null);
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean shouldIgnore(ClassInfo ci) {
+ return
+ ci.hasAnnotation(BeanIgnore.class)
+ || ci.isNonStaticMemberClass()
+ || ci.isPrimitive()
+ || ci.isChildOf(Number.class);
+ }
+
+ private static boolean isSwapMethod(MethodInfo mi) {
+ ClassInfo rt = mi.getReturnType();
+ return
+ mi.isNotDeprecated()
+ && mi.isNotStatic()
+ && (rt.isChildOf(Number.class) || (rt.isPrimitive() && rt.isAny(int.class, short.class, long.class, float.class, double.class, byte.class)))
+ && mi.hasName(SWAP_METHOD_NAMES)
+ && mi.hasFuzzyParamTypes(BeanSession.class)
+ && ! mi.hasAnnotation(BeanIgnore.class);
+ }
+
+ private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+ return
+ mi.isNotDeprecated()
+ && mi.isStatic()
+ && mi.hasName(UNSWAP_METHOD_NAMES)
+ && mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
+ && mi.hasReturnTypeParent(ci)
+ && ! mi.hasAnnotation(BeanIgnore.class);
+ }
+
+ private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+ return
+ cs.isNotDeprecated()
+ && cs.hasParamTypeParents(rt)
+ && ! cs.hasAnnotation(BeanIgnore.class);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+
+ private final Method swapMethod, unswapMethod;
+ private final Constructor<?> unswapConstructor;
+ private final Class<?> unswapType;
+
+ private AutoNumberSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+ super(ci.inner(), swapMethod.inner().getReturnType());
+ this.swapMethod = swapMethod.inner();
+ this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
+ this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+
+ Class<?> unswapType = null;
+ if (unswapMethod != null) {
+ for (ParamInfo pi : unswapMethod.getParams())
+ if (! pi.getParameterType().is(BeanSession.class))
+ unswapType = pi.getParameterType().getWrapperIfPrimitive();
+ } else if (unswapConstructor != null) {
+ for (ParamInfo pi : unswapConstructor.getParams())
+ if (! pi.getParameterType().is(BeanSession.class))
+ unswapType = pi.getParameterType().getWrapperIfPrimitive();
+ }
+ this.unswapType = unswapType;
+ }
+
+ @Override /* PojoSwap */
+ public Number swap(BeanSession session, Object o) throws SerializeException {
+ try {
+ return (Number)swapMethod.invoke(o, getMatchingArgs(swapMethod.getParameterTypes(), session));
+ } catch (Exception e) {
+ throw SerializeException.create(e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override /* PojoSwap */
+ public T unswap(BeanSession session, Number o, ClassMeta<?> hint) throws ParseException {
+ try {
+ Object o2 = ObjectUtils.toType(o, unswapType);
+ if (unswapMethod != null)
+ return (T)unswapMethod.invoke(null, getMatchingArgs(unswapMethod.getParameterTypes(), session, o2));
+ if (unswapConstructor != null)
+ return (T)unswapConstructor.newInstance(o2);
+ return super.unswap(session, o, hint);
+ } catch (Exception e) {
+ throw ParseException.create(e);
+ }
+ }
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java
new file mode 100644
index 0000000..a55f700
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java
@@ -0,0 +1,183 @@
+// ***************************************************************************************************************************
+// * 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.juneau.transform;
+
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ClassUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * A dynamic POJO swap based on reflection of a Java class that converts POJOs to serializable objects.
+ *
+ * <p>
+ * Looks for methods on the class that can be called to swap-in surrogate objects before serialization and swap-out
+ * surrogate objects after parsing.
+ *
+ * <h5 class='figure'>Valid surrogate objects</h5>
+ * <ul>
+ * <li class='jc'>{@link String}
+ * <li class='jc'>{@link Number}
+ * <li class='jc'>{@link Boolean}
+ * <li class='jc'>{@link Map}
+ * <li class='jc'>{@link Collection}
+ * </ul>
+ *
+ * <h5 class='figure'>Valid swap methods (S = Swapped type)</h5>
+ * <ul>
+ * <li class='jm'><c><jk>public</jk> S swap()</c>
+ * <li class='jm'><c><jk>public</jk> S swap(BeanSession)</c>
+ * <li class='jm'><c><jk>public</jk> S toObject()</c>
+ * <li class='jm'><c><jk>public</jk> S toObject(BeanSession)</c>
+ * </ul>
+ *
+ * <h5 class='figure'>Valid unswap methods (N = Normal type, S = Swapped type)</h5>
+ * <ul>
+ * <li class='jm'><c><jk>public static</jk> N unswap(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N unswap(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromObject(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromObject(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public static</jk> N create(S)</c>
+ * <li class='jm'><c><jk>public static</jk> N create(BeanSession, S)</c>
+ * <li class='jm'><c><jk>public</jk> N(S)</c>
+ * </ul>
+ *
+ * <p>
+ * Classes are ignored if any of the following are true:
+ * <ul>
+ * <li>Classes annotated with {@link BeanIgnore @BeanIgnore}.
+ * <li>Non-static member classes.
+ * </ul>
+ *
+ * <p>
+ * Members/constructors are ignored if any of the following are true:
+ * <ul>
+ * <li>Members/constructors annotated with {@link BeanIgnore @BeanIgnore}.
+ * <li>Deprecated members/constructors.
+ * </ul>
+ *
+ * @param <T> The normal class type.
+ */
+public class AutoObjectSwap<T> extends PojoSwap<T,Object> {
+
+ private static final Set<String>
+ SWAP_METHOD_NAMES = newUnmodifiableHashSet("swap", "toObject"),
+ UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("unswap", "create", "fromObject");
+
+ /**
+ * Inspects the specified class and returns a swap of this type if possible.
+ *
+ * @param ci The class to return a swap on.
+ * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
+ */
+ @SuppressWarnings({ "rawtypes" })
+ public static PojoSwap<?,?> find(ClassInfo ci) {
+
+ if (shouldIgnore(ci))
+ return null;
+
+ // Find swap() method if present.
+ for (MethodInfo m : ci.getPublicMethods()) {
+ if (isSwapMethod(m)) {
+
+ ClassInfo rt = m.getReturnType();
+
+ for (MethodInfo m2 : ci.getPublicMethods())
+ if (isUnswapMethod(m2, ci, rt))
+ return new AutoObjectSwap(ci, m, m2, null);
+
+ for (ConstructorInfo cs : ci.getPublicConstructors())
+ if (isUnswapConstructor(cs, rt))
+ return new AutoObjectSwap(ci, m, null, cs);
+
+ return new AutoObjectSwap(ci, m, null, null);
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean shouldIgnore(ClassInfo ci) {
+ return
+ ci.hasAnnotation(BeanIgnore.class)
+ || ci.isNonStaticMemberClass();
+ }
+
+ private static boolean isSwapMethod(MethodInfo mi) {
+ return
+ mi.isNotDeprecated()
+ && mi.isNotStatic()
+ && mi.hasName(SWAP_METHOD_NAMES)
+ && mi.hasFuzzyParamTypes(BeanSession.class)
+ && ! mi.hasAnnotation(BeanIgnore.class);
+ }
+
+ private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+ return
+ mi.isNotDeprecated()
+ && mi.isStatic()
+ && mi.hasName(UNSWAP_METHOD_NAMES)
+ && mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
+ && mi.hasReturnTypeParent(ci)
+ && ! mi.hasAnnotation(BeanIgnore.class);
+ }
+
+ private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+ return
+ cs.isNotDeprecated()
+ && cs.hasParamTypeParents(rt)
+ && ! cs.hasAnnotation(BeanIgnore.class);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+
+ private final Method swapMethod, unswapMethod;
+ private final Constructor<?> unswapConstructor;
+
+ private AutoObjectSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+ super(ci.inner(), swapMethod.inner().getReturnType());
+ this.swapMethod = swapMethod.inner();
+ this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
+ this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+ }
+
+ @Override /* PojoSwap */
+ public Object swap(BeanSession session, Object o) throws SerializeException {
+ try {
+ return swapMethod.invoke(o, getMatchingArgs(swapMethod.getParameterTypes(), session));
+ } catch (Exception e) {
+ throw SerializeException.create(e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override /* PojoSwap */
+ public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException {
+ try {
+ if (unswapMethod != null)
+ return (T)unswapMethod.invoke(null, getMatchingArgs(unswapMethod.getParameterTypes(), session, f));
+ if (unswapConstructor != null)
+ return (T)unswapConstructor.newInstance(f);
+ return super.unswap(session, f, hint);
+ } catch (Exception e) {
+ throw ParseException.create(e);
+ }
+ }
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoStringSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoStringSwap.java
new file mode 100644
index 0000000..dc8b6c2
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoStringSwap.java
@@ -0,0 +1,147 @@
+// ***************************************************************************************************************************
+// * 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.juneau.transform;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * A dynamic POJO swap based on reflection of a Java class that converts POJOs to serializable String objects.
+ *
+ * <p>
+ * Looks for methods on the class that can be called to swap-in surrogate String objects before serialization and swap-out
+ * surrogate String objects after parsing.
+ *
+ * <h5 class='figure'>Valid unswap methods (N = Normal type)</h5>
+ * <ul>
+ * <li class='jm'><c><jk>public static</jk> N fromString(String)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromString(BeanSession, String)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromValue(String)</c>
+ * <li class='jm'><c><jk>public static</jk> N fromValue(BeanSession, String)</c>
+ * <li class='jm'><c><jk>public static</jk> N valueOf(String)</c>
+ * <li class='jm'><c><jk>public static</jk> N valueOf(BeanSession, String)</c>
+ * <li class='jm'><c><jk>public static</jk> N parse(String)</c>
+ * <li class='jm'><c><jk>public static</jk> N parse(BeanSession, String)</c>
+ * <li class='jm'><c><jk>public static</jk> N parseString(String)</c>
+ * <li class='jm'><c><jk>public static</jk> N parseString(BeanSession, String)</c>
+ * <li class='jm'><c><jk>public static</jk> N forName(String)</c>
+ * <li class='jm'><c><jk>public static</jk> N forName(BeanSession, String)</c>
+ * <li class='jm'><c><jk>public static</jk> N forString(String)</c>
+ * <li class='jm'><c><jk>public static</jk> N forString(BeanSession, String)</c>
+ * <li class='jm'><c><jk>public</jk> N(String)</c>
+ * </ul>
+ *
+ * <p>
+ * Classes are ignored if any of the following are true:
+ * <ul>
+ * <li>Classes annotated with {@link BeanIgnore @BeanIgnore}.
+ * <li>Non-static member classes.
+ * </ul>
+ *
+ * <p>
+ * Members/constructors are ignored if any of the following are true:
+ * <ul>
+ * <li>Members/constructors annotated with {@link BeanIgnore @BeanIgnore}.
+ * <li>Deprecated members/constructors.
+ * </ul>
+ *
+ * @param <T> The normal class type.
+ */
+public class AutoStringSwap<T> extends org.apache.juneau.transform.StringSwap<T> {
+
+ private static final Set<String>
+ UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("fromString", "fromValue", "valueOf", "parse", "parseString", "forName", "forString");
+
+ /**
+ * Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
+ *
+ * @param ci The class to try to constructor a dynamic swap on.
+ * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
+ */
+ @SuppressWarnings({ "rawtypes" })
+ public static PojoSwap<?,?> find(ClassInfo ci) {
+
+ if (shouldIgnore(ci))
+ return null;
+
+ for (MethodInfo m : ci.getPublicMethods())
+ if (isUnswapMethod(m, ci))
+ return new AutoStringSwap(ci, m, null);
+
+ for (ConstructorInfo cs : ci.getPublicConstructors())
+ if (isUnswapConstructor(cs))
+ return new AutoStringSwap(ci, null, cs);
+
+ return null;
+ }
+
+ private static boolean shouldIgnore(ClassInfo ci) {
+ return
+ ci.hasAnnotation(BeanIgnore.class)
+ || ci.isNonStaticMemberClass();
+ }
+
+ private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci) {
+ return
+ mi.isNotDeprecated()
+ && mi.isStatic()
+ && mi.hasName(UNSWAP_METHOD_NAMES)
+ && mi.hasFuzzyParamTypes(BeanSession.class, String.class)
+ && mi.hasReturnTypeParent(ci)
+ && ! mi.hasAnnotation(BeanIgnore.class);
+ }
+
+ private static boolean isUnswapConstructor(ConstructorInfo cs) {
+ return
+ cs.isNotDeprecated()
+ && cs.hasParamTypes(String.class)
+ && ! cs.hasAnnotation(BeanIgnore.class);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+
+ private final Method unswapMethod;
+ private final Constructor<?> unswapConstructor;
+
+ private AutoStringSwap(ClassInfo ci, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+ super(ci.inner());
+ this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
+ this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+ }
+
+ @Override /* PojoSwap */
+ public String swap(BeanSession session, T o) throws SerializeException {
+ return o.toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override /* PojoSwap */
+ public T unswap(BeanSession session, String f, ClassMeta<?> hint) throws ParseException {
+ try {
+ if (unswapMethod != null)
+ return (T)unswapMethod.invoke(null, getMatchingArgs(unswapMethod.getParameterTypes(), session, f));
+ return (T)unswapConstructor.newInstance(f);
+ } catch (Exception e) {
+ throw ParseException.create(e);
+ }
+ }
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/DynamicSwaps.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/DynamicSwaps.java
deleted file mode 100644
index 25b0242..0000000
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/DynamicSwaps.java
+++ /dev/null
@@ -1,129 +0,0 @@
-// ***************************************************************************************************************************
-// * 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.juneau.transform;
-
-import static org.apache.juneau.reflect.ReflectFlags.*;
-
-import java.lang.reflect.*;
-import java.util.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.annotation.*;
-import org.apache.juneau.internal.*;
-import org.apache.juneau.parser.*;
-import org.apache.juneau.reflect.*;
-import org.apache.juneau.serializer.*;
-
-/**
- * A dynamic POJO swap based on reflection of a Java class.
- */
-public class DynamicSwaps {
-
- /**
- * Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
- *
- * @param ci The class to try to constructor a dynamic swap on.
- * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public static PojoSwap<?,?> find(ClassInfo ci) {
-
- if (ci.hasAnnotation(BeanIgnore.class))
- return null;
-
- Class<?> c = ci.inner();
- boolean isMemberClass = ci.isMemberClass() && ci.isNotStatic();
-
- // Find swap() method if present.
- for (MethodInfo m : ci.getPublicMethods()) {
- if (m.isAll(PUBLIC, NOT_DEPRECATED, NOT_STATIC) && (m.hasName("swap") || m.hasName("toMap")) && m.hasFuzzyArgs(BeanSession.class)) {
-
- Class<?> swapMethodType = m.getReturnType().inner();
-
- for (MethodInfo m2 : ci.getPublicMethods()) {
- if (m2.isAll(PUBLIC, NOT_DEPRECATED, STATIC) && (m2.hasName("unswap") || m2.hasName("fromMap")) && m2.hasFuzzyArgs(BeanSession.class, swapMethodType)) {
- return new SwapMethodsSwap(c, m, m2);
- }
- }
-
- for (ConstructorInfo cs : ci.getPublicConstructors()) {
- if (cs.isPublic() && cs.isNotDeprecated()) {
- List<ClassInfo> pt = cs.getParamTypes();
- if (pt.size() == (isMemberClass ? 2 : 1)) {
- ClassInfo arg = pt.get(isMemberClass ? 1 : 0);
- if (swapMethodType != null && arg.isChildOf(swapMethodType))
- return new SwapMethodsSwap(c, m, cs);
- }
- }
- }
-
- return new SwapMethodsSwap(c, m);
- }
- }
-
- return null;
- }
-
-
- //------------------------------------------------------------------------------------------------------------------
- // POJO swap for class with swap/unswap methods.
- //------------------------------------------------------------------------------------------------------------------
-
- private static class SwapMethodsSwap<T> extends PojoSwap<T,Object> {
-
- private final Method swapMethod, unswapMethod;
- private final Constructor<?> swapConstructor;
-
- public SwapMethodsSwap(Class<T> c, MethodInfo swapMethod, MethodInfo unswapMethod) {
- this(c, swapMethod.inner(), unswapMethod.inner(), null);
- }
-
- public SwapMethodsSwap(Class<T> c, MethodInfo swapMethod, ConstructorInfo swapConstructor) {
- this(c, swapMethod.inner(), null, swapConstructor.inner());
- }
-
- public SwapMethodsSwap(Class<T> c, MethodInfo swapMethod) {
- this(c, swapMethod.inner(), null, null);
- }
-
- SwapMethodsSwap(Class<T> c, Method swapMethod, Method unswapMethod, Constructor<?> swapConstructor) {
- super(c, swapMethod.getReturnType());
- this.swapMethod = swapMethod;
- this.unswapMethod = unswapMethod;
- this.swapConstructor = swapConstructor;
- }
-
- @Override
- public Object swap(BeanSession session, Object o) throws SerializeException {
- try {
- return swapMethod.invoke(o, ClassUtils.getMatchingArgs(swapMethod.getParameterTypes(), session));
- } catch (Exception e) {
- throw new SerializeException(e);
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException {
- try {
- if (unswapMethod != null)
- return (T)unswapMethod.invoke(null, ClassUtils.getMatchingArgs(swapMethod.getParameterTypes(), session, f));
- if (swapConstructor != null)
- return (T)swapConstructor.newInstance(f);
- return super.unswap(session, f, hint);
- } catch (Exception e) {
- throw new ParseException(e);
- }
- }
- }
-}
diff --git a/juneau-doc/docs/Topics/02.juneau-marshall/11.Transforms/02.DefaultPojoSwaps.html b/juneau-doc/docs/Topics/02.juneau-marshall/11.Transforms/02.DefaultPojoSwaps.html
index fad76c5..d76af81 100644
--- a/juneau-doc/docs/Topics/02.juneau-marshall/11.Transforms/02.DefaultPojoSwaps.html
+++ b/juneau-doc/docs/Topics/02.juneau-marshall/11.Transforms/02.DefaultPojoSwaps.html
@@ -13,7 +13,7 @@
***************************************************************************************************************************/
-->
-{new} Default PojoSwaps
+{todo} Default PojoSwaps
<p>
By default, all serializers and parsers have built in <c>PojoSwaps</c> defined for the following common data types: