001 /*
002 * Java Genetic Algorithm Library (jenetics-1.6.0).
003 * Copyright (c) 2007-2014 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
019 */
020 package org.jenetics.internal.util;
021
022 import static org.jenetics.internal.util.reflect.classOf;
023
024 import java.util.HashMap;
025 import java.util.List;
026 import java.util.Map;
027
028 import javax.xml.bind.JAXBContext;
029 import javax.xml.bind.JAXBElement;
030 import javax.xml.bind.JAXBException;
031 import javax.xml.bind.annotation.adapters.XmlAdapter;
032 import javax.xml.transform.dom.DOMResult;
033 import javax.xml.transform.dom.DOMSource;
034
035 import org.w3c.dom.Document;
036 import org.w3c.dom.Element;
037
038 import org.jscience.mathematics.number.Float64;
039 import org.jscience.mathematics.number.Integer64;
040
041 import org.jenetics.internal.util.model.BooleanModel;
042 import org.jenetics.internal.util.model.ByteModel;
043 import org.jenetics.internal.util.model.CharacterModel;
044 import org.jenetics.internal.util.model.DoubleModel;
045 import org.jenetics.internal.util.model.Float64Model;
046 import org.jenetics.internal.util.model.FloatModel;
047 import org.jenetics.internal.util.model.Integer64Model;
048 import org.jenetics.internal.util.model.IntegerModel;
049 import org.jenetics.internal.util.model.LongModel;
050 import org.jenetics.internal.util.model.ModelType;
051 import org.jenetics.internal.util.model.ShortModel;
052 import org.jenetics.internal.util.model.StringModel;
053 import org.jenetics.internal.util.model.ValueType;
054
055 import org.jenetics.util.Function;
056 import org.jenetics.util.StaticObject;
057
058 /**
059 * JAXB helper methods.
060 *
061 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
062 * @version 1.6 — <em>$Date: 2014-02-02 $</em>
063 * @since 1.6
064 */
065 public class jaxb extends StaticObject {
066 private jaxb() {}
067
068 public static final JAXBContext CONTEXT = newContext();
069
070 private static JAXBContext newContext() {
071 try {
072 return JAXBContext.newInstance(
073 "org.jenetics:org.jenetics.internal.util"
074 );
075 } catch (JAXBException e) {
076 throw new AssertionError(e);
077 }
078 }
079
080 private static final XmlAdapter<Object, Object> IdentityAdapter =
081 new XmlAdapter<Object, Object>() {
082 @Override public Object unmarshal(final Object value) {
083 return value;
084 }
085 @Override public Object marshal(final Object value) {
086 return value;
087 }
088 };
089
090 private static final Map<Class<?>, XmlAdapter<? extends Object, ? extends Object>>
091 ADAPTER_CACHE = new HashMap<>();
092
093 static {
094 ADAPTER_CACHE.put(Boolean.class, BooleanModel.Adapter);
095 ADAPTER_CACHE.put(BooleanModel.class, BooleanModel.Adapter);
096
097 ADAPTER_CACHE.put(Byte.class, ByteModel.Adapter);
098 ADAPTER_CACHE.put(ByteModel.class, ByteModel.Adapter);
099
100 ADAPTER_CACHE.put(Character.class, CharacterModel.Adapter);
101 ADAPTER_CACHE.put(CharacterModel.class, CharacterModel.Adapter);
102
103 ADAPTER_CACHE.put(Short.class, ShortModel.Adapter);
104 ADAPTER_CACHE.put(ShortModel.class, ShortModel.Adapter);
105
106 ADAPTER_CACHE.put(Integer.class, IntegerModel.Adapter);
107 ADAPTER_CACHE.put(IntegerModel.class, IntegerModel.Adapter);
108
109 ADAPTER_CACHE.put(Long.class, LongModel.Adapter);
110 ADAPTER_CACHE.put(LongModel.class, LongModel.Adapter);
111
112 ADAPTER_CACHE.put(Float.class, FloatModel.Adapter);
113 ADAPTER_CACHE.put(FloatModel.class, FloatModel.Adapter);
114
115 ADAPTER_CACHE.put(Double.class, DoubleModel.Adapter);
116 ADAPTER_CACHE.put(DoubleModel.class, DoubleModel.Adapter);
117
118 ADAPTER_CACHE.put(String.class, StringModel.Adapter);
119 ADAPTER_CACHE.put(StringModel.class, StringModel.Adapter);
120
121 ADAPTER_CACHE.put(Integer64.class, Integer64Model.Adapter);
122 ADAPTER_CACHE.put(Integer64Model.class, Integer64Model.Adapter);
123
124 ADAPTER_CACHE.put(Float64.class, Float64Model.Adapter);
125 ADAPTER_CACHE.put(Float64Model.class, Float64Model.Adapter);
126 }
127
128 /**
129 * Return the an {@code XmlAdapter} for the given {@code vale}. If no
130 * adapter could be found, and identity adapter is returned.
131 *
132 * @param value the object for which to find an {@code XmlAdapter}
133 * @return the {@code XmlAdapter} for the given object, or an identity
134 * adapter if no one can be found.
135 */
136 @SuppressWarnings("unchecked")
137 public static XmlAdapter<Object, Object> adapterFor(final Object value) {
138 final Class<?> cls = classOf(value);
139
140 synchronized (ADAPTER_CACHE) {
141 if (!ADAPTER_CACHE.containsKey(cls)) {
142 ADAPTER_CACHE.put(cls, newXmlAdapter(cls));
143 }
144
145 return (XmlAdapter<Object, Object>)ADAPTER_CACHE.get(cls);
146 }
147 }
148
149 @SuppressWarnings("unchecked")
150 private static XmlAdapter<Object, Object> newXmlAdapter(final Class<?> cls) {
151 final List<Class<?>> classes = reflect.allDeclaredClasses(cls);
152
153 XmlAdapter<Object, Object> adapter = IdentityAdapter;
154 for (int i = 0; i < classes.size() && adapter == IdentityAdapter; ++i) {
155 if (XmlAdapter.class.isAssignableFrom(classes.get(i))) {
156 try {
157 adapter = (XmlAdapter<Object, Object>)classes.get(i).newInstance();
158 } catch (InstantiationException | IllegalAccessException e) {
159 // ignore exception
160 }
161 }
162 }
163
164 return adapter;
165 }
166
167 /**
168 * Return the model type (Class<?>) for the given object. If the given
169 * object is its own model, {@code value.getClass()} is returned.
170 *
171 * @param value the object we try to find the model type.
172 * @return the model type of the given value.
173 */
174 public static Class<?> modelTypeFor(final Object value) {
175 Class<?> modelType = classOf(value);
176
177 final Object adapter = adapterFor(value);
178 final ModelType ma = adapter.getClass().getAnnotation(ModelType.class);
179 if (ma != null) {
180 modelType = ma.value();
181 }
182
183 return modelType;
184 }
185
186 /**
187 * Return the value type (Class<?>) for the given object. If the given
188 * object is its own value, {@code value.getClass()} is returned.
189 *
190 * @param value the object we try to find the value type.
191 * @return the value type of the given value.
192 */
193 public static Class<?> valueTypeFor(final Object value) {
194 Class<?> valueType = classOf(value);
195
196 final Object adapter = adapterFor(value);
197 final ValueType ma = adapter.getClass().getAnnotation(ValueType.class);
198 if (ma != null) {
199 valueType = ma.value();
200 }
201
202 return valueType;
203 }
204
205 /**
206 * Shorthand for {@code adapterFor(value).marshal(value)}
207 */
208 public static Object marshal(final Object value) throws Exception {
209 return adapterFor(value).marshal(value);
210 }
211
212 /**
213 * Shorthand for {@code adapterFor(value).unmarshal(value)}
214 */
215 public static Object unmarshal(final Object value) throws Exception {
216 return adapterFor(value).unmarshal(value);
217 }
218
219 /**
220 * Return a marshaller function from the given
221 * {@link javax.xml.bind.annotation.adapters.XmlAdapter}.
222 *
223 * @param a the adapter used by the marshaller function.
224 * @return the marshaller function
225 */
226 public static <V, B> Function<B, V> Marshaller(final XmlAdapter<V, B> a) {
227 return new Function<B, V>() {
228 @Override
229 public V apply(final B value) {
230 try {
231 return a.marshal(value);
232 } catch (Exception e) {
233 throw new RuntimeException(e);
234 }
235 }
236 };
237 }
238
239 /**
240 * Return a unmarshaller function from the given
241 * {@link javax.xml.bind.annotation.adapters.XmlAdapter}.
242 *
243 * @param a the adapter used by the unmarshaller function.
244 * @return the unmarshaller function
245 */
246 public static <V, B> Function<V, B> Unmarshaller(final XmlAdapter<V, B> a) {
247 return new Function<V, B>() {
248 @Override
249 public B apply(final V value) {
250 try {
251 return a.unmarshal(value);
252 } catch (Exception e) {
253 throw new RuntimeException(e);
254 }
255 }
256 };
257 }
258
259 /**
260 * Return a marshaller function for the given object.
261 *
262 * @param value the value to marshal
263 * @return the marshaller function
264 */
265 public static Function<Object, Object> Marshaller(final Object value) {
266 return Marshaller(adapterFor(value));
267 }
268
269 /**
270 * Return a unmarshaller function for the given object.
271 *
272 * @param value the value to unmarshal
273 * @return the unmarshaller function
274 */
275 public static Function<Object, Object> Unmarshaller(final Object value) {
276 return Unmarshaller(jaxb.adapterFor(value));
277 }
278
279 /**
280 * An generic unmarshaller function.
281 */
282 public static final Function<Object, Object> Unmarshaller =
283 new Function<Object, Object>() {
284 @SuppressWarnings("rawtypes")
285 @Override
286 public Object apply(final Object value) {
287 Object result = value;
288 if (value instanceof Element) {
289 final Element element = (Element)value;
290
291 try {
292 final Class<?> type = modelTypeFor(
293 Class.forName(element.getNodeName())
294 );
295
296 final DOMSource source = new DOMSource(element);
297 final JAXBElement jaxbElement = CONTEXT.createUnmarshaller()
298 .unmarshal(source, type);
299
300 result = jaxb.adapterFor(jaxbElement.getValue())
301 .unmarshal(jaxbElement.getValue());
302 } catch (Exception e) {
303 throw new RuntimeException(e);
304 }
305 }
306
307 return result;
308 }
309 };
310
311 public static final class JavolutionElementAdapter
312 extends XmlAdapter<Object, Object>
313 {
314 @SuppressWarnings("rawtypes")
315 @Override
316 public Object unmarshal(final Object v) throws Exception {
317 final Element element = (Element)v;
318 final Class<?> type = modelTypeFor(
319 Class.forName(element.getAttribute("class"))
320 );
321
322 final DOMSource source = new DOMSource(element);
323 final JAXBElement jaxbElement = CONTEXT.createUnmarshaller()
324 .unmarshal(source, type);
325
326 return jaxb.adapterFor(jaxbElement.getValue())
327 .unmarshal(jaxbElement.getValue());
328 }
329
330 @Override
331 public Object marshal(final Object v) throws Exception {
332 final DOMResult result = new DOMResult();
333 CONTEXT.createMarshaller().marshal(v, result);
334
335 final Element e = ((Document)result.getNode()).getDocumentElement();
336 final Class<?> type = valueTypeFor(v);
337 e.setAttribute("class", type.getCanonicalName());
338
339 return e;
340 }
341 }
342
343 }
|