001/* 002 * Java Genetic Algorithm Library (jenetics-3.9.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 */ 020package org.jenetics.util; 021 022import static org.jenetics.internal.util.JAXBContextCache.context; 023import static org.jenetics.internal.util.jaxb.adapterFor; 024import static org.jenetics.internal.util.jaxb.marshal; 025 026import java.io.File; 027import java.io.FileInputStream; 028import java.io.FileOutputStream; 029import java.io.IOException; 030import java.io.InputStream; 031import java.io.ObjectInputStream; 032import java.io.ObjectOutputStream; 033import java.io.OutputStream; 034import java.nio.file.Path; 035import java.util.Arrays; 036 037import javax.xml.bind.Marshaller; 038import javax.xml.bind.Unmarshaller; 039import javax.xml.bind.annotation.adapters.XmlAdapter; 040 041import org.jenetics.internal.util.JAXBContextCache; 042import 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 */ 089public 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 * @deprecated Since the {@code javax.xml.bind} is marked as deprecated for 117 * removal in Java 9, the JAXB marshalling will be removed as 118 * well. Use the {@code org.jenetics.xml} module when writing 119 * and reading Jenetics data-objects as XML. 120 * 121 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a> 122 * @since 3.5 123 * @version 3.5 124 */ 125 @Deprecated 126 public static final class JAXB { 127 private JAXB() {require.noInstance();} 128 129 /** 130 * Registers the given <em>JAXB</em> model classes. This allows to use 131 * the {@code IO.jaxb} class with own <em>JAXB</em> marshallings. 132 * <p> 133 * <em>It is safe to call this method more than once for a given class. 134 * The class is registered only once.</em> 135 * 136 * @param classes the <em>JAXB</em> model classes to register 137 * @throws NullPointerException if one of the classes is {@code null} 138 */ 139 public static void register(final Class<?>... classes) { 140 Arrays.asList(classes).forEach(JAXBContextCache::add); 141 } 142 143 /** 144 * De-registers the given <em>JAXB</em> model classes. 145 * 146 * @param classes the <em>JAXB</em> model classes to register 147 * @throws NullPointerException if one of the classes is {@code null} 148 */ 149 public static void deregister(final Class<?>... classes) { 150 Arrays.asList(classes).forEach(JAXBContextCache::remove); 151 } 152 153 /** 154 * Check is the given class is already registered. 155 * 156 * @param cls the class to check 157 * @return {@code true} if the given class is already registered, 158 * {@code false} otherwise. 159 */ 160 public static boolean contains(final Class<?> cls) { 161 return JAXBContextCache.contains(cls); 162 } 163 } 164 165 /** 166 * JAXB for <i>XML</i> serialization. 167 * 168 * @deprecated Since the {@code javax.xml.bind} is marked as deprecated for 169 * removal in Java 9, the JAXB marshalling will be removed as 170 * well. Use the {@code org.jenetics.xml} module when writing 171 * and reading Jenetics data-objects as XML. 172 */ 173 @Deprecated 174 public static final IO jaxb = new IO() { 175 176 @Override 177 public void write(final Object object, final OutputStream out) 178 throws IOException 179 { 180 try { 181 final Marshaller marshaller = context().createMarshaller(); 182 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 183 marshaller.marshal(marshal(object), out); 184 } catch (Exception e) { 185 throw new IOException(e); 186 } 187 } 188 189 @Override 190 public <T> T read(final Class<T> type, final InputStream in) 191 throws IOException 192 { 193 try { 194 final Unmarshaller unmarshaller = context().createUnmarshaller(); 195 196 //final XMLInputFactory factory = XMLInputFactory.newInstance(); 197 //final XMLStreamReader reader = factory.createXMLStreamReader(in); 198 //try { 199 final Object object = unmarshaller.unmarshal(in); 200 final XmlAdapter<Object, Object> adapter = adapterFor(object); 201 if (adapter != null) { 202 return type.cast(adapter.unmarshal(object)); 203 } else { 204 return type.cast(object); 205 } 206 //} finally { 207 // reader.close(); 208 //} 209 } catch (Exception e) { 210 throw new IOException(e); 211 } 212 } 213 }; 214 215 /** 216 * IO implementation for "native" <i>Java</i> serialization. 217 */ 218 public static final IO object = new IO() { 219 220 @Override 221 public void write(final Object object, final OutputStream out) 222 throws IOException 223 { 224 final ObjectOutputStream oout = new ObjectOutputStream(out); 225 oout.writeObject(object); 226 out.flush(); 227 } 228 229 @Override 230 public <T> T read(final Class<T> type, final InputStream in) 231 throws IOException 232 { 233 final ObjectInputStream oin = new ObjectInputStream(in); 234 try { 235 return type.cast(oin.readObject()); 236 } catch (ClassNotFoundException | ClassCastException e) { 237 throw new IOException(e); 238 } 239 } 240 }; 241 242 243 /** 244 * Write the (serializable) object to the given path. 245 * 246 * @param object the object to serialize. 247 * @param path the path to write the object to. 248 * @throws NullPointerException if one of the arguments is {@code null}. 249 * @throws IOException if the object could not be serialized. 250 */ 251 public void write(final Object object, final String path) 252 throws IOException 253 { 254 write(object, new File(path)); 255 } 256 257 /** 258 * Write the (serializable) object to the given path. 259 * 260 * @param object the object to serialize. 261 * @param path the path to write the object to. 262 * @throws NullPointerException if one of the arguments is {@code null}. 263 * @throws IOException if the object could not be serialized. 264 */ 265 public void write(final Object object, final Path path) 266 throws IOException 267 { 268 write(object, path.toFile()); 269 } 270 271 /** 272 * Write the (serializable) object to the given file. 273 * 274 * @param object the object to serialize. 275 * @param file the file to write the object to. 276 * @throws NullPointerException if one of the arguments is {@code null}. 277 * @throws IOException if the object could not be serialized. 278 */ 279 public void write(final Object object, final File file) 280 throws IOException 281 { 282 try (final FileOutputStream out = new FileOutputStream(file)) { 283 write(object, out); 284 } 285 } 286 287 /** 288 * Write the (serializable) object to the given output stream. 289 * 290 * @param object the object to serialize. 291 * @param out the output stream to write the object to. 292 * @throws NullPointerException if one of the arguments is {@code null}. 293 * @throws IOException if the object could not be serialized. 294 */ 295 public abstract void write(final Object object, final OutputStream out) 296 throws IOException; 297 298 /** 299 * Reads an object from the given file. 300 * 301 * @param <T> the type of the read object 302 * @param path the path to read from. 303 * @param type the type of the read object. 304 * @return the de-serialized object. 305 * @throws NullPointerException if the input stream {@code in} is {@code null}. 306 * @throws IOException if the object could not be read. 307 */ 308 public <T> T read(final Class<T> type, final String path) 309 throws IOException 310 { 311 try (final FileInputStream in = new FileInputStream(new File(path))) { 312 return read(type, in); 313 } 314 } 315 316 /** 317 * Reads an object from the given file. 318 * 319 * @param path the path to read from. 320 * @return the de-serialized object. 321 * @throws NullPointerException if the input stream {@code in} is {@code null}. 322 * @throws IOException if the object could not be read. 323 */ 324 public Object read(final String path) throws IOException { 325 return read(Object.class, path); 326 } 327 328 /** 329 * Reads an object from the given file. 330 * 331 * @param <T> the type of the read object 332 * @param path the path to read from. 333 * @param type the type of the read object. 334 * @return the de-serialized object. 335 * @throws NullPointerException if the input stream {@code in} is {@code null}. 336 * @throws IOException if the object could not be read. 337 */ 338 public <T> T read(final Class<T> type, final Path path) 339 throws IOException 340 { 341 try (final FileInputStream in = new FileInputStream(path.toFile())) { 342 return read(type, in); 343 } 344 } 345 346 /** 347 * Reads an object from the given file. 348 * 349 * @param path the path to read from. 350 * @return the de-serialized object. 351 * @throws NullPointerException if the input stream {@code in} is {@code null}. 352 * @throws IOException if the object could not be read. 353 */ 354 public Object read(final Path path) throws IOException { 355 return read(Object.class, path); 356 } 357 358 /** 359 * Reads an object from the given file. 360 * 361 * @param <T> the type of the read object 362 * @param file the file to read from. 363 * @param type the type of the read object. 364 * @return the de-serialized object. 365 * @throws NullPointerException if the input stream {@code in} is {@code null}. 366 * @throws IOException if the object could not be read. 367 */ 368 public <T> T read(final Class<T> type, final File file) 369 throws IOException 370 { 371 try (final FileInputStream in = new FileInputStream(file)) { 372 return read(type, in); 373 } 374 } 375 376 /** 377 * Reads an object from the given file. 378 * 379 * @param file the file to read from. 380 * @return the de-serialized object. 381 * @throws NullPointerException if the input stream {@code in} is {@code null}. 382 * @throws IOException if the object could not be read. 383 */ 384 public Object read(final File file) throws IOException { 385 return read(Object.class, file); 386 } 387 388 /** 389 * Reads an object from the given input stream. 390 * 391 * @param <T> the type of the read object 392 * @param in the input stream to read from. 393 * @param type the type of the read object. 394 * @return the de-serialized object. 395 * @throws NullPointerException if the input stream {@code in} is {@code null}. 396 * @throws IOException if the object could not be read. 397 */ 398 public abstract <T> T read(final Class<T> type, final InputStream in) 399 throws IOException; 400 401 /** 402 * Reads an object from the given input stream. 403 * 404 * @param in the input stream to read from. 405 * @return the de-serialized object. 406 * @throws NullPointerException if the input stream {@code in} is {@code null}. 407 * @throws IOException if the object could not be read. 408 */ 409 public Object read(final InputStream in) throws IOException { 410 return read(Object.class, in); 411 } 412}