blob: ec1cd9f8a6e91d135a36a20ea2250f54a5900261 [file] [log] [blame]
// ***************************************************************************************************************************
// * 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.a.rttests;
import static org.apache.juneau.internal.DateUtils.*;
import static org.apache.juneau.testutils.TestUtils.*;
import static org.junit.Assert.*;
import java.io.*;
import java.util.*;
import javax.xml.datatype.*;
import org.apache.juneau.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.json.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.serializer.*;
import org.apache.juneau.testutils.*;
import org.apache.juneau.transform.*;
import org.apache.juneau.transforms.*;
import org.apache.juneau.utils.*;
import org.junit.*;
/**
* Tests designed to serialize and parse objects to make sure we end up
* with the same objects for all serializers and parsers.
*/
@SuppressWarnings({"unchecked","rawtypes","serial"})
public class RoundTripTransformBeansTest extends RoundTripTest {
public RoundTripTransformBeansTest(String label, SerializerBuilder s, ParserBuilder p, int flags) throws Exception {
super(label, s == null ? null : s.applyAnnotations(Bc.class, E1c.class, F1c.class, F2ac.class), p == null ? null : p.applyAnnotations(Bc.class, E1c.class, F1c.class, F2ac.class), flags);
}
//====================================================================================================
// testSwapBeans1
//====================================================================================================
@Test
public void testSwapBeans1() throws Exception {
Class<?>[] f = {
ByteArraySwap.Base64.class
};
pojoSwaps(f);
A t = new A().init();
t = roundTrip(t, A.class);
// ByteArrayBase64Swap
assertEquals(3, t.fByte[3]);
assertNull(t.fnByte);
assertEquals(5, t.faByte[2][1]);
assertEquals(6, t.flByte.get(1)[2]);
assertNull(t.flByte.get(2));
assertEquals(6, t.fmByte.get("bar")[2]);
assertNull(t.fmByte.get("baz"));
// CalendarSwap
t.fCalendar.setTimeZone(TimeZone.getTimeZone("GMT"));
assertEquals(2001, t.fCalendar.get(Calendar.YEAR));
assertEquals(01, t.fCalendar.get(Calendar.MONTH));
assertEquals(02, t.fCalendar.get(Calendar.DATE));
assertEquals(03, t.fCalendar.get(Calendar.HOUR));
assertEquals(04, t.fCalendar.get(Calendar.MINUTE));
assertEquals(05, t.fCalendar.get(Calendar.SECOND));
t.faCalendar[0].setTimeZone(TimeZone.getTimeZone("GMT"));
assertEquals(2001, t.faCalendar[0].get(Calendar.YEAR));
assertEquals(01, t.faCalendar[0].get(Calendar.MONTH));
assertEquals(02, t.faCalendar[0].get(Calendar.DATE));
assertEquals(03, t.faCalendar[0].get(Calendar.HOUR));
assertEquals(04, t.faCalendar[0].get(Calendar.MINUTE));
assertEquals(05, t.faCalendar[0].get(Calendar.SECOND));
assertNull(t.fnCalendar);
assertNull(t.fn2Calendar);
// DateSwap
assertEquals(1000, t.fDate.getTime());
assertNull(t.fnDate);
assertEquals(3000, t.faDate[2].getTime());
assertEquals(4000, t.flDate.get(0).getTime());
assertNull(t.flDate.get(1));
assertEquals(5000, t.fmDate.get("foo").getTime());
assertNull(t.fmDate.get("bar"));
}
public static class A {
// Test ByteArrayBase64Swap
public byte[] fByte;
public byte[] fnByte;
public byte[][] faByte;
public List<byte[]> flByte;
public Map<String,byte[]> fmByte;
public GregorianCalendar fCalendar;
public GregorianCalendar fnCalendar;
public Calendar fn2Calendar;
public GregorianCalendar[] faCalendar;
public Date fDate;
public Date fnDate;
public Date[] faDate;
public List<Date> flDate;
public Map<String,Date> fmDate;
public A init() {
fByte = new byte[]{0,1,2,3};
fnByte = null;
faByte = new byte[][]{{0,1},{2,3},{4,5}};
flByte = new AList<byte[]>()
.append(new byte[]{1,2,3})
.append(new byte[]{4,5,6})
.append(null)
;
fmByte = new AMap<String,byte[]>()
.append("foo", new byte[]{1,2,3})
.append("bar", new byte[]{4,5,6})
.append("baz", null)
;
fCalendar = new GregorianCalendar() {{
set(2001, 01, 02, 03, 04, 05);
setTimeZone(TimeZone.getTimeZone("GMT"));
}};
fnCalendar = null;
fn2Calendar = null;
faCalendar = new GregorianCalendar[]{
new GregorianCalendar() {{
set(2001, 01, 02, 03, 04, 05);
setTimeZone(TimeZone.getTimeZone("GMT"));
}}
};
fDate = new Date(1000);
fnDate = null;
faDate = new Date[]{
new Date(1000), new Date(2000), new Date(3000)
};
flDate = new AList<Date>()
.append(new Date(4000))
.append(null)
;
fmDate = new AMap<String,Date>()
.append("foo", new Date(5000))
.append("bar", null)
;
return this;
}
}
//====================================================================================================
// testSwapBeans2
//====================================================================================================
@Test
public void testSwapBeans2() throws Exception {
Class<?>[] f = {
ByteArraySwap.Base64.class
};
pojoSwaps(f);
A t = new A().init();
t = roundTrip(t, A.class);
// ByteArrayBase64Swap
assertEquals(3, t.fByte[3]);
assertNull(t.fnByte);
assertEquals(5, t.faByte[2][1]);
assertEquals(6, t.flByte.get(1)[2]);
assertNull(t.flByte.get(2));
assertEquals(6, t.fmByte.get("bar")[2]);
assertNull(t.fmByte.get("baz"));
// CalendarSwap
t.fCalendar.setTimeZone(TimeZone.getTimeZone("GMT"));
assertEquals(2001, t.fCalendar.get(Calendar.YEAR));
assertEquals(01, t.fCalendar.get(Calendar.MONTH));
// Note: We lose precision on the following because of the transform type.
//assertEquals(02, b.fCalendar.get(Calendar.DATE));
//assertEquals(03, b.fCalendar.get(Calendar.HOUR));
//assertEquals(04, b.fCalendar.get(Calendar.MINUTE));
//assertEquals(05, b.fCalendar.get(Calendar.SECOND));
t.faCalendar[0].setTimeZone(TimeZone.getTimeZone("GMT"));
assertEquals(2001, t.faCalendar[0].get(Calendar.YEAR));
assertEquals(01, t.faCalendar[0].get(Calendar.MONTH));
// Note: We lose precision on the following because of the transform type.
//assertEquals(02, b.faCalendar[0].get(Calendar.DATE));
//assertEquals(03, b.faCalendar[0].get(Calendar.HOUR));
//assertEquals(04, b.faCalendar[0].get(Calendar.MINUTE));
//assertEquals(05, b.faCalendar[0].get(Calendar.SECOND));
assertNull(t.fnCalendar);
assertNull(t.fn2Calendar);
// DateSwap
assertEquals(1000, t.fDate.getTime() % 3600000);
assertNull(t.fnDate);
assertEquals(3000, t.faDate[2].getTime() % 3600000);
assertEquals(4000, t.flDate.get(0).getTime() % 3600000);
assertNull(t.flDate.get(1));
assertEquals(5000, t.fmDate.get("foo").getTime() % 3600000);
assertNull(t.fmDate.get("bar"));
}
//====================================================================================================
// testSwaps - Bean.pojoSwaps annotation
//====================================================================================================
@Test
public void testSwaps() throws Exception {
B t = new B();
t.f1 = "bar";
t = roundTrip(t, B.class);
assertEquals("bar", t.f1);
}
@Swap(BSwap.class)
public static class B {
public String f1;
}
public static class BSwap extends StringSwap<B> {
@Override /* PojoSwap */
public String swap(BeanSession session, B o) throws SerializeException {
return o.f1;
}
@Override /* PojoSwap */
public B unswap(BeanSession session, String f, ClassMeta<?> hint) throws ParseException {
B b1 = new B();
b1.f1 = f;
return b1;
}
}
@Test
public void testSwaps_usingConfig() throws Exception {
Bc t = new Bc();
t.f1 = "bar";
t = roundTrip(t, Bc.class);
assertEquals("bar", t.f1);
}
@BeanConfig(applySwap=@Swap(on="Bc",value=BcSwap.class))
public static class Bc {
public String f1;
}
public static class BcSwap extends StringSwap<Bc> {
@Override /* PojoSwap */
public String swap(BeanSession session, Bc o) throws SerializeException {
return o.f1;
}
@Override /* PojoSwap */
public Bc unswap(BeanSession session, String f, ClassMeta<?> hint) throws ParseException {
Bc b1 = new Bc();
b1.f1 = f;
return b1;
}
}
//====================================================================================================
// testXMLGregorianCalendar - Test XMLGregorianCalendarSwap class.
//====================================================================================================
@Test
public void testXMLGregorianCalendar() throws Exception {
if (isValidationOnly())
return;
GregorianCalendar gc = new GregorianCalendar();
XMLGregorianCalendar c = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
Serializer s = getSerializer();
Parser p = getParser();
Object r = s.serialize(c);
XMLGregorianCalendar c2 = p.parse(r, XMLGregorianCalendar.class);
assertEquals(c, c2);
}
//====================================================================================================
// testSubTypeWithGenerics
//====================================================================================================
@Test
public void testSubTypeWithGenerics() throws Exception {
JsonSerializer s = JsonSerializer.DEFAULT.builder().addBeanTypes().addRootType().build();
C1 c1 = C3.create();
String r = s.serialize(c1);
assertEquals("{\"_type\":\"C3\",\"f1\":{\"f2\":\"f2\",\"f3\":3}}", r);
}
@Bean(dictionary={C3.class})
public static interface C1<T> extends Serializable {
void setF1(T f1);
T getF1();
}
public abstract static class C2<T> implements C1<T> {
protected T f1;
@Override /* C1 */
public void setF1(T f1) {
this.f1 = f1;
}
@Override /* C1 */
public T getF1() {
return f1;
}
}
@Bean(typeName="C3")
public static class C3<T> extends C2<T> {
public static C3 create() {
C3 c3 = new C3<>();
CDTO cdto = new CDTO();
cdto.f2 = "f2";
cdto.f3 = 3;
c3.f1 = cdto;
return c3;
}
@Override /* C1 */
public void setF1(T f1) {
this.f1 = f1;
}
@Override /* C1 */
public T getF1() {
return f1;
}
}
public static class CDTO {
public String f2;
public int f3;
}
//====================================================================================================
// Surrogate transforms
//====================================================================================================
@Test
public void testSurrogates() throws Exception {
pojoSwaps(D2.class);
JsonSerializer s = JsonSerializer.create().ssq().pojoSwaps(D2.class).build();
JsonParser p = JsonParser.create().pojoSwaps(D2.class).build();
Object r;
D1 x = D1.create();
r = s.serialize(x);
assertEquals("{f2:'f1'}", r);
x = p.parse(r, D1.class);
assertEquals("f1", x.f1);
r = getSerializer().serialize(x);
assertTrue(TestUtils.toString(r).contains("f2"));
x = roundTrip(x, D1.class);
}
public static class D1 {
public String f1;
public static D1 create() {
D1 x = new D1();
x.f1 = "f1";
return x;
}
}
public static class D2 implements Surrogate {
public String f2;
public D2(D1 x) {
f2 = x.f1;
}
public D2() {}
public D1 create() {
D1 x = new D1();
x.f1 = this.f2;
return x;
}
}
@Test
public void testSurrogatesThroughAnnotation() throws Exception {
JsonSerializer s = SimpleJsonSerializer.DEFAULT;
JsonParser p = JsonParser.DEFAULT;
Object r;
E1 x = E1.create();
r = s.serialize(x);
assertEquals("{f2:'f1'}", r);
x = p.parse(r, E1.class);
assertEquals("f1", x.f1);
r = getSerializer().serialize(x);
assertTrue(TestUtils.toString(r).contains("f2"));
x = roundTrip(x, E1.class);
}
@Swap(E2.class)
public static class E1 {
public String f1;
public static E1 create() {
E1 x = new E1();
x.f1 = "f1";
return x;
}
}
public static class E2 implements Surrogate {
public String f2;
public E2(E1 x) {
f2 = x.f1;
}
public E2() {}
public E1 create() {
E1 x = new E1();
x.f1 = this.f2;
return x;
}
}
@Test
public void testSurrogatesThroughAnnotation_usingConfig() throws Exception {
JsonSerializer s = SimpleJsonSerializer.DEFAULT.builder().applyAnnotations(E1c.class).build();
JsonParser p = JsonParser.DEFAULT.builder().applyAnnotations(E1c.class).build();
Object r;
E1c x = E1c.create();
r = s.serialize(x);
assertEquals("{f2:'f1'}", r);
x = p.parse(r, E1c.class);
assertEquals("f1", x.f1);
r = getSerializer().serialize(x);
assertTrue(TestUtils.toString(r).contains("f2"));
x = roundTrip(x, E1c.class);
}
@BeanConfig(applySwap=@Swap(on="E1c",value=E2c.class))
public static class E1c {
public String f1;
public static E1c create() {
E1c x = new E1c();
x.f1 = "f1";
return x;
}
}
public static class E2c implements Surrogate {
public String f2;
public E2c(E1c x) {
f2 = x.f1;
}
public E2c() {}
public E1c create() {
E1c x = new E1c();
x.f1 = this.f2;
return x;
}
}
//====================================================================================================
// Transforms on private fields.
//====================================================================================================
public static class F1 {
@Swap(TemporalCalendarSwap.IsoLocalDateTime.class)
private Calendar c;
public void setC(Calendar c) {
this.c = c;
}
public Calendar getC() {
return c;
}
public static F1 create() {
F1 x = new F1();
x.setC(parseISO8601Calendar("2018-12-12T05:12:00"));
return x;
}
}
@Test
public void testSwapOnPrivateField() throws Exception {
JsonSerializer s = SimpleJsonSerializer.DEFAULT;
JsonParser p = JsonParser.DEFAULT;
F1 x = F1.create();
String r = null;
r = s.serialize(x);
assertEquals("{c:'2018-12-12T05:12:00'}", r);
x = p.parse(r, F1.class);
assertObjectEquals("{c:'2018-12-12T05:12:00'}", x);
x = roundTrip(x, F1.class);
}
@BeanConfig(applySwap=@Swap(on="F1c.c", value=TemporalCalendarSwap.IsoLocalDateTime.class))
public static class F1c {
private Calendar c;
public void setC(Calendar c) {
this.c = c;
}
public Calendar getC() {
return c;
}
public static F1c create() {
F1c x = new F1c();
x.setC(parseISO8601Calendar("2018-12-12T05:12:00"));
return x;
}
}
@Test
public void testSwapOnPrivateField_usingConfig() throws Exception {
JsonSerializer s = SimpleJsonSerializer.DEFAULT.builder().applyAnnotations(F1c.class).build();
JsonParser p = JsonParser.DEFAULT.builder().applyAnnotations(F1c.class).build();
F1c x = F1c.create();
String r = null;
r = s.serialize(x);
assertEquals("{c:'2018-12-12T05:12:00'}", r);
x = p.parse(r, F1c.class);
assertObjectEquals("{c:'2018-12-12T05:12:00'}", x, s);
x = roundTrip(x, F1c.class);
}
public static class F2a {
@Swap(TemporalCalendarSwap.IsoLocalDateTime.class)
protected Calendar c;
}
public static class F2 extends F2a {
public void setC(Calendar c) {
this.c = c;
}
public Calendar getC() {
return c;
}
public static F2 create() {
F2 x = new F2();
x.setC(parseISO8601Calendar("2018-12-12T05:12:00"));
return x;
}
}
@Test
public void testSwapOnPrivateField_Inherited() throws Exception {
JsonSerializer s = SimpleJsonSerializer.DEFAULT;
JsonParser p = JsonParser.DEFAULT;
F2 x = F2.create();
String r = null;
r = s.serialize(x);
assertEquals("{c:'2018-12-12T05:12:00'}", r);
x = p.parse(r, F2.class);
assertObjectEquals("{c:'2018-12-12T05:12:00'}", x);
x = roundTrip(x, F2.class);
}
@BeanConfig(applySwap=@Swap(on="F2ac.c", value=TemporalCalendarSwap.IsoLocalDateTime.class))
public static class F2ac {
protected Calendar c;
}
public static class F2c extends F2ac {
public void setC(Calendar c) {
this.c = c;
}
public Calendar getC() {
return c;
}
public static F2c create() {
F2c x = new F2c();
x.setC(parseISO8601Calendar("2018-12-12T05:12:00"));
return x;
}
}
@Test
public void testSwapOnPrivateField_Inherited_usingConfig() throws Exception {
JsonSerializer s = SimpleJsonSerializer.DEFAULT.builder().applyAnnotations(F2ac.class).build();
JsonParser p = JsonParser.DEFAULT.builder().applyAnnotations(F2ac.class).build();
F2 x = F2.create();
String r = null;
r = s.serialize(x);
assertEquals("{c:'2018-12-12T05:12:00'}", r);
x = p.parse(r, F2.class);
assertObjectEquals("{c:'2018-12-12T05:12:00'}", x, s);
x = roundTrip(x, F2.class);
}
}