001 /*
002 * Java Genetic Algorithm Library (jenetics-3.8.0).
003 * Copyright (c) 2007-2017 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.util;
021
022 import static org.jenetics.internal.util.JAXBContextCache.context;
023 import static org.jenetics.internal.util.jaxb.adapterFor;
024 import static org.jenetics.internal.util.jaxb.marshal;
025
026 import java.io.File;
027 import java.io.FileInputStream;
028 import java.io.FileOutputStream;
029 import java.io.IOException;
030 import java.io.InputStream;
031 import java.io.ObjectInputStream;
032 import java.io.ObjectOutputStream;
033 import java.io.OutputStream;
034 import java.nio.file.Path;
035 import java.util.Arrays;
036
037 import javax.xml.bind.Marshaller;
038 import javax.xml.bind.Unmarshaller;
039 import javax.xml.bind.annotation.adapters.XmlAdapter;
040
041 import org.jenetics.internal.util.JAXBContextCache;
042 import org.jenetics.internal.util.require;
043
044 /**
045 * Class for object serialization. The following example shows how to write and
046 * reload a given population.
047 *
048 * <pre>{@code
049 * // Creating result population.
050 * EvolutionResult<DoubleGene, Double> result = stream
051 * .collect(toBestEvolutionResult());
052 *
053 * // Writing the population to disk.
054 * final File file = new File("population.xml");
055 * IO.jaxb.write(result.getPopulation(), file);
056 *
057 * // Reading the population from disk.
058 * Population<DoubleGene, Double> population =
059 * (Population<DoubleGene, Double>)IO.jaxb.read(file);
060 * EvolutionStream<DoubleGene, Double> stream = Engine
061 * .build(ff, gtf)
062 * .stream(population, 1);
063 * }</pre>
064 *
065 * The {@code jaxb} marshalling also allows to read and write own classes. For
066 * this you have to register your {@code @XmlType}d class first.
067 * <pre>{@code
068 * // The user defined 'JAXB' model class.
069 * \@XmlRootElement(name = "data-class")
070 * \@XmlType(name = "DataClass")
071 * \@XmlAccessorType(XmlAccessType.FIELD)
072 * public static final class DataClass {
073 * \@XmlAttribute public String name;
074 * \@XmlValue public String value;
075 * }
076 *
077 * // Register the 'JAXB' model class.
078 * IO.JAXB.register(DataClass.class);
079 * final DataClass data = ...;
080 * IO.jaxb.write(data, "data.xml");
081 * }</pre>
082 *
083 * It is safe to call {@code IO.JAXB.register(DataClass.class)} more than once.
084 *
085 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
086 * @since 1.0
087 * @version 3.5
088 */
089 public abstract class IO {
090
091 protected IO() {
092 }
093
094 /**
095 * Helper class for <em>JAXB</em> class registering/de-registering.
096 *
097 * <pre>{@code
098 * // The user defined 'JAXB' model class.
099 * \@XmlRootElement(name = "data-class")
100 * \@XmlType(name = "DataClass")
101 * \@XmlAccessorType(XmlAccessType.FIELD)
102 * public static final class DataClass {
103 * \@XmlAttribute public String name;
104 * \@XmlValue public String value;
105 * }
106 *
107 * // Register the 'JAXB' model class.
108 * IO.JAXB.register(DataClass.class);
109 * final DataClass data = ...;
110 * IO.jaxb.write(data, "data.xml");
111 * }</pre>
112 *
113 * It is safe to call {@code IO.JAXB.register(DataClass.class)} more than
114 * once.
115 *
116 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
117 * @since 3.5
118 * @version 3.5
119 */
120 public static final class JAXB {
121 private JAXB() {require.noInstance();}
122
123 /**
124 * Registers the given <em>JAXB</em> model classes. This allows to use
125 * the {@code IO.jaxb} class with own <em>JAXB</em> marshallings.
126 * <p>
127 * <em>It is safe to call this method more than once for a given class.
128 * The class is registered only once.</em>
129 *
130 * @param classes the <em>JAXB</em> model classes to register
131 * @throws NullPointerException if one of the classes is {@code null}
132 */
133 public static void register(final Class<?>... classes) {
134 Arrays.asList(classes).forEach(JAXBContextCache::add);
135 }
136
137 /**
138 * De-registers the given <em>JAXB</em> model classes.
139 *
140 * @param classes the <em>JAXB</em> model classes to register
141 * @throws NullPointerException if one of the classes is {@code null}
142 */
143 public static void deregister(final Class<?>... classes) {
144 Arrays.asList(classes).forEach(JAXBContextCache::remove);
145 }
146
147 /**
148 * Check is the given class is already registered.
149 *
150 * @param cls the class to check
151 * @return {@code true} if the given class is already registered,
152 * {@code false} otherwise.
153 */
154 public static boolean contains(final Class<?> cls) {
155 return JAXBContextCache.contains(cls);
156 }
157 }
158
159 /**
160 * JAXB for <i>XML</i> serialization.
161 */
162 public static final IO jaxb = new IO() {
163
164 @Override
165 public void write(final Object object, final OutputStream out)
166 throws IOException
167 {
168 try {
169 final Marshaller marshaller = context().createMarshaller();
170 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
171 marshaller.marshal(marshal(object), out);
172 } catch (Exception e) {
173 throw new IOException(e);
174 }
175 }
176
177 @Override
178 public <T> T read(final Class<T> type, final InputStream in)
179 throws IOException
180 {
181 try {
182 final Unmarshaller unmarshaller = context().createUnmarshaller();
183
184 //final XMLInputFactory factory = XMLInputFactory.newInstance();
185 //final XMLStreamReader reader = factory.createXMLStreamReader(in);
186 //try {
187 final Object object = unmarshaller.unmarshal(in);
188 final XmlAdapter<Object, Object> adapter = adapterFor(object);
189 if (adapter != null) {
190 return type.cast(adapter.unmarshal(object));
191 } else {
192 return type.cast(object);
193 }
194 //} finally {
195 // reader.close();
196 //}
197 } catch (Exception e) {
198 throw new IOException(e);
199 }
200 }
201 };
202
203 /**
204 * IO implementation for "native" <i>Java</i> serialization.
205 */
206 public static final IO object = new IO() {
207
208 @Override
209 public void write(final Object object, final OutputStream out)
210 throws IOException
211 {
212 final ObjectOutputStream oout = new ObjectOutputStream(out);
213 oout.writeObject(object);
214 out.flush();
215 }
216
217 @Override
218 public <T> T read(final Class<T> type, final InputStream in)
219 throws IOException
220 {
221 final ObjectInputStream oin = new ObjectInputStream(in);
222 try {
223 return type.cast(oin.readObject());
224 } catch (ClassNotFoundException | ClassCastException e) {
225 throw new IOException(e);
226 }
227 }
228 };
229
230
231 /**
232 * Write the (serializable) object to the given path.
233 *
234 * @param object the object to serialize.
235 * @param path the path to write the object to.
236 * @throws NullPointerException if one of the arguments is {@code null}.
237 * @throws IOException if the object could not be serialized.
238 */
239 public void write(final Object object, final String path)
240 throws IOException
241 {
242 write(object, new File(path));
243 }
244
245 /**
246 * Write the (serializable) object to the given path.
247 *
248 * @param object the object to serialize.
249 * @param path the path to write the object to.
250 * @throws NullPointerException if one of the arguments is {@code null}.
251 * @throws IOException if the object could not be serialized.
252 */
253 public void write(final Object object, final Path path)
254 throws IOException
255 {
256 write(object, path.toFile());
257 }
258
259 /**
260 * Write the (serializable) object to the given file.
261 *
262 * @param object the object to serialize.
263 * @param file the file to write the object to.
264 * @throws NullPointerException if one of the arguments is {@code null}.
265 * @throws IOException if the object could not be serialized.
266 */
267 public void write(final Object object, final File file)
268 throws IOException
269 {
270 try (final FileOutputStream out = new FileOutputStream(file)) {
271 write(object, out);
272 }
273 }
274
275 /**
276 * Write the (serializable) object to the given output stream.
277 *
278 * @param object the object to serialize.
279 * @param out the output stream to write the object to.
280 * @throws NullPointerException if one of the arguments is {@code null}.
281 * @throws IOException if the object could not be serialized.
282 */
283 public abstract void write(final Object object, final OutputStream out)
284 throws IOException;
285
286 /**
287 * Reads an object from the given file.
288 *
289 * @param <T> the type of the read object
290 * @param path the path to read from.
291 * @param type the type of the read object.
292 * @return the de-serialized object.
293 * @throws NullPointerException if the input stream {@code in} is {@code null}.
294 * @throws IOException if the object could not be read.
295 */
296 public <T> T read(final Class<T> type, final String path)
297 throws IOException
298 {
299 try (final FileInputStream in = new FileInputStream(new File(path))) {
300 return read(type, in);
301 }
302 }
303
304 /**
305 * Reads an object from the given file.
306 *
307 * @param path the path to read from.
308 * @return the de-serialized object.
309 * @throws NullPointerException if the input stream {@code in} is {@code null}.
310 * @throws IOException if the object could not be read.
311 */
312 public Object read(final String path) throws IOException {
313 return read(Object.class, path);
314 }
315
316 /**
317 * Reads an object from the given file.
318 *
319 * @param <T> the type of the read object
320 * @param path the path to read from.
321 * @param type the type of the read object.
322 * @return the de-serialized object.
323 * @throws NullPointerException if the input stream {@code in} is {@code null}.
324 * @throws IOException if the object could not be read.
325 */
326 public <T> T read(final Class<T> type, final Path path)
327 throws IOException
328 {
329 try (final FileInputStream in = new FileInputStream(path.toFile())) {
330 return read(type, in);
331 }
332 }
333
334 /**
335 * Reads an object from the given file.
336 *
337 * @param path the path to read from.
338 * @return the de-serialized object.
339 * @throws NullPointerException if the input stream {@code in} is {@code null}.
340 * @throws IOException if the object could not be read.
341 */
342 public Object read(final Path path) throws IOException {
343 return read(Object.class, path);
344 }
345
346 /**
347 * Reads an object from the given file.
348 *
349 * @param <T> the type of the read object
350 * @param file the file to read from.
351 * @param type the type of the read object.
352 * @return the de-serialized object.
353 * @throws NullPointerException if the input stream {@code in} is {@code null}.
354 * @throws IOException if the object could not be read.
355 */
356 public <T> T read(final Class<T> type, final File file)
357 throws IOException
358 {
359 try (final FileInputStream in = new FileInputStream(file)) {
360 return read(type, in);
361 }
362 }
363
364 /**
365 * Reads an object from the given file.
366 *
367 * @param file the file to read from.
368 * @return the de-serialized object.
369 * @throws NullPointerException if the input stream {@code in} is {@code null}.
370 * @throws IOException if the object could not be read.
371 */
372 public Object read(final File file) throws IOException {
373 return read(Object.class, file);
374 }
375
376 /**
377 * Reads an object from the given input stream.
378 *
379 * @param <T> the type of the read object
380 * @param in the input stream to read from.
381 * @param type the type of the read object.
382 * @return the de-serialized object.
383 * @throws NullPointerException if the input stream {@code in} is {@code null}.
384 * @throws IOException if the object could not be read.
385 */
386 public abstract <T> T read(final Class<T> type, final InputStream in)
387 throws IOException;
388
389 /**
390 * Reads an object from the given input stream.
391 *
392 * @param in the input stream to read from.
393 * @return the de-serialized object.
394 * @throws NullPointerException if the input stream {@code in} is {@code null}.
395 * @throws IOException if the object could not be read.
396 */
397 public Object read(final InputStream in) throws IOException {
398 return read(Object.class, in);
399 }
400 }
|