View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.a.rttests;
18  
19  import static java.util.Collections.*;
20  import static java.util.Optional.*;
21  import static org.apache.juneau.TestUtils.*;
22  import java.lang.reflect.*;
23  import java.util.*;
24  
25  import org.apache.juneau.common.utils.*;
26  import org.apache.juneau.parser.*;
27  import org.apache.juneau.serializer.*;
28  import org.apache.juneau.xml.*;
29  
30  @SuppressWarnings("unchecked")
31  public class RoundTrip_Tester {
32  
33  	public static Builder create(int index, String label) {
34  		return new Builder().index(index).label(label);
35  	}
36  
37  	static class Builder {
38  
39  		private int index;
40  		public Builder index(int value) { index = value; return this; }
41  
42  		private String label;
43  		public Builder label(String value) { label = value; return this; }
44  
45  		private Serializer.Builder s;
46  		public Builder serializer(Serializer.Builder value) { s = value; return this; }
47  
48  		private Parser.Builder p;
49  		public Builder parser(Parser.Builder value) { p = value; return this; }
50  
51  		private boolean validateXmlWhitespace;
52  		public Builder validateXmlWhitespace() { validateXmlWhitespace = true; return this; }
53  
54  		private boolean returnOriginalObject;
55  		public Builder returnOriginalObject() { returnOriginalObject = true; return this; }
56  
57  		private boolean validateXml;
58  		public Builder validateXml() { validateXml = true; return this; }
59  
60  		private boolean debug;
61  		public Builder debug() { debug = true; return this; }
62  
63  		private Map<Class<?>,Class<?>> implClasses = emptyMap();
64  		public Builder implClasses(Map<Class<?>,Class<?>> value) { implClasses = value; return this; }
65  
66  		private Class<?>[] pojoSwaps = a();
67  		public Builder pojoSwaps(Class<?>...value) { pojoSwaps = value; return this; }
68  
69  		private Class<?>[] dictionary = a();
70  		public Builder dictionary(Class<?>...value) { dictionary = value; return this; }
71  
72  		private Class<?>[] annotatedClasses = a();
73  		public Builder annotatedClasses(Class<?>...value) { annotatedClasses = value; return this; }
74  
75  		public RoundTrip_Tester build() {
76  			return new RoundTrip_Tester(this);
77  		}
78  	}
79  
80  	protected String label;
81  	protected Serializer s;
82  	protected Parser p;
83  	private boolean validateXmlWhitespace;
84  	protected boolean returnOriginalObject;
85  	private boolean validateXml;
86  	public boolean debug;
87  
88  	private RoundTrip_Tester(Builder b) {
89  		label = "[" + b.index + "] " + b.label;
90  
91  		var bs = b.s;
92  		var bp = ofNullable(b.p);
93  
94  		if (! (b.implClasses.isEmpty() && b.pojoSwaps.length == 0 && b.dictionary.length == 0 && b.annotatedClasses.length == 0)) {
95  			bs = bs.copy();
96  			bp = bp.map(Parser.Builder::copy);
97  			for (var e : b.implClasses.entrySet()) {
98  				bs.implClass(e.getKey(), e.getValue());
99  				bp.ifPresent(x -> x.implClass(e.getKey(), e.getValue()));
100 			}
101 			bs.swaps(b.pojoSwaps).beanDictionary(b.dictionary).applyAnnotations(b.annotatedClasses);
102 			bp.ifPresent(x -> x.swaps(b.pojoSwaps).beanDictionary(b.dictionary).applyAnnotations(b.annotatedClasses));
103 		}
104 
105 		s = bs.build();
106 		p = bp.map(Parser.Builder::build).orElse(null);
107 		validateXmlWhitespace = b.validateXmlWhitespace;
108 		validateXml = b.validateXml;
109 		returnOriginalObject = b.returnOriginalObject;
110 		debug = b.debug;
111 	}
112 
113 	public <T> T roundTrip(T object, Type c, Type...args) throws Exception {
114 		var out = serialize(object, s);
115 		if (p == null)
116 			return object;
117 		var o = (T)p.parse(out, c, args);
118 		return (returnOriginalObject ? object : o);
119 	}
120 
121 	public <T> T roundTrip(T object) throws Exception {
122 		return roundTrip(object, s, p);
123 	}
124 
125 	public <T> T roundTrip(T object, Serializer serializer, Parser parser) throws Exception {
126 		var out = serialize(object, serializer);
127 		if (parser == null)
128 			return object;
129 		var o = (T)parser.parse(out,  object == null ? Object.class : object.getClass());
130 		return (returnOriginalObject ? object : o);
131 	}
132 
133 	public Serializer getSerializer() {
134 		return s;
135 	}
136 
137 	public Parser getParser() {
138 		return p;
139 	}
140 
141 	public boolean isValidationOnly() {
142 		return returnOriginalObject;
143 	}
144 
145 	public <T> Object serialize(T object, Serializer s) throws Exception {
146 
147 		Object out = null;
148 		if (s.isWriterSerializer())
149 			out = ((WriterSerializer)s).serialize(object);
150 		else {
151 			out = ((OutputStreamSerializer)s).serialize(object);
152 		}
153 
154 		if (debug)
155 			System.err.println("Serialized contents from ["+label+"]...\n---START---\n" + (out instanceof byte[] ? StringUtils.toReadableBytes((byte[])out) : out) + "\n---END---\n"); // NOT DEBUG
156 
157 		if (validateXmlWhitespace)
158 			checkXmlWhitespace(out.toString());
159 
160 		if (validateXml)
161 			validateXml(object, (XmlSerializer)s);
162 
163 		return out;
164 	}
165 }