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 */ 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 * @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}