001/*
002 * Java Genetic Algorithm Library (jenetics-8.1.0).
003 * Copyright (c) 2007-2024 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@gmail.com)
019 */
020package io.jenetics.util;
021
022import java.io.ByteArrayInputStream;
023import java.io.ByteArrayOutputStream;
024import java.io.File;
025import java.io.FileInputStream;
026import java.io.FileOutputStream;
027import java.io.IOException;
028import java.io.InputStream;
029import java.io.ObjectInputStream;
030import java.io.ObjectOutputStream;
031import java.io.OutputStream;
032import java.nio.file.Path;
033
034/**
035 * Class for object serialization. The following example shows how to write and
036 * reload a given population.
037 * <p>
038 * {@snippet lang="java":
039 * // Creating result population.
040 * EvolutionResult<DoubleGene, Double> result = stream
041 *     .collect(toBestEvolutionResult());
042 *
043 * // Writing the population to disk.
044 * final File file = new File("population.bin");
045 * IO.object.write(result.getPopulation(), file);
046 *
047 * // Reading the population from disk.
048 * ISeq<Phenotype<G, C>> population = (ISeq<Phenotype<G, C>>)IO.object.read(file);
049 * EvolutionStream<DoubleGene, Double> stream = Engine
050 *     .build(ff, gtf)
051 *     .stream(population, 1);
052 * }
053 *
054 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
055 * @since 1.0
056 * @version 4.0
057 */
058public abstract class IO {
059
060        protected IO() {
061        }
062
063        /**
064         * IO implementation for "native" <i>Java</i> serialization.
065         */
066        public static final IO object = new IO() {
067
068                @Override
069                public void write(final Object object, final OutputStream out)
070                        throws IOException
071                {
072                        final ObjectOutputStream oout = new ObjectOutputStream(out);
073                        oout.writeObject(object);
074                        out.flush();
075                }
076
077                @Override
078                public <T> T read(final Class<T> type, final InputStream in)
079                        throws IOException
080                {
081                        final ObjectInputStream oin = new ObjectInputStream(in);
082                        try {
083                                return type.cast(oin.readObject());
084                        } catch (ClassNotFoundException | ClassCastException e) {
085                                throw new IOException(e);
086                        }
087                }
088        };
089
090        /**
091         * Serializes the given {@code object} to a {@code byte[]} array.
092         *
093         * @since 4.1
094         *
095         * @param object the object to serialize.
096         * @throws NullPointerException if one of the objects is {@code null}.
097         * @throws IOException if the object could not be serialized.
098         * @return the serialized {@code object} as {@code byte[]} array
099         */
100        public byte[] toByteArray(final Object object) throws IOException {
101                final ByteArrayOutputStream out = new ByteArrayOutputStream();
102                write(object, out);
103                return out.toByteArray();
104        }
105
106        /**
107         * Write the (serializable) object to the given path.
108         *
109         * @param object the object to serialize.
110         * @param path the path to write the object to.
111         * @throws NullPointerException if one of the arguments is {@code null}.
112         * @throws IOException if the object could not be serialized.
113         */
114        public void write(final Object object, final String path)
115                throws IOException
116        {
117                write(object, new File(path));
118        }
119
120        /**
121         * Write the (serializable) object to the given path.
122         *
123         * @param object the object to serialize.
124         * @param path the path to write the object to.
125         * @throws NullPointerException if one of the arguments is {@code null}.
126         * @throws IOException if the object could not be serialized.
127         */
128        public void write(final Object object, final Path path)
129                throws IOException
130        {
131                write(object, path.toFile());
132        }
133
134        /**
135         * Write the (serializable) object to the given file.
136         *
137         * @param object the object to serialize.
138         * @param file the file to write the object to.
139         * @throws NullPointerException if one of the arguments is {@code null}.
140         * @throws IOException if the object could not be serialized.
141         */
142        public void write(final Object object, final File file)
143                throws IOException
144        {
145                try (final FileOutputStream out = new FileOutputStream(file)) {
146                        write(object, out);
147                }
148        }
149
150        /**
151         * Write the (serializable) object to the given output stream.
152         *
153         * @param object the object to serialize.
154         * @param out the output stream to write the object to.
155         * @throws NullPointerException if one of the arguments is {@code null}.
156         * @throws IOException if the object could not be serialized.
157         */
158        public abstract void write(final Object object, final OutputStream out)
159                throws IOException;
160
161        /**
162         * Creates a, previously serialized, object from the given {@code byte[]}
163         * array.
164         *
165         * @since 4.1
166         *
167         * @param bytes the serialized object.
168         * @return the deserialized object.
169         * @throws NullPointerException if the input {@code bytes} is {@code null}.
170         * @throws IOException if the object could not be deserialized.
171         */
172        public Object fromByteArray(final byte[] bytes) throws IOException {
173                final ByteArrayInputStream in = new ByteArrayInputStream(bytes);
174                return read(in);
175        }
176
177        /**
178         * Reads an object from the given file.
179         *
180         * @param <T> the type of the read object
181         * @param path the path to read from.
182         * @param type the type of the read object.
183         * @return the deserialized object.
184         * @throws NullPointerException if the input stream {@code in} is {@code null}.
185         * @throws IOException if the object could not be read.
186         */
187        public <T> T read(final Class<T> type, final String path)
188                throws IOException
189        {
190                try (final FileInputStream in = new FileInputStream(new File(path))) {
191                        return read(type, in);
192                }
193        }
194
195        /**
196         * Reads an object from the given file.
197         *
198         * @param path the path to read from.
199         * @return the deserialized object.
200         * @throws NullPointerException if the input stream {@code in} is {@code null}.
201         * @throws IOException if the object could not be read.
202         */
203        public Object read(final String path) throws IOException {
204                return read(Object.class, path);
205        }
206
207        /**
208         * Reads an object from the given file.
209         *
210         * @param <T> the type of the read object
211         * @param path the path to read from.
212         * @param type the type of the read object.
213         * @return the deserialized object.
214         * @throws NullPointerException if the input stream {@code in} is {@code null}.
215         * @throws IOException if the object could not be read.
216         */
217        public <T> T read(final Class<T> type, final Path path)
218                throws IOException
219        {
220                try (final FileInputStream in = new FileInputStream(path.toFile())) {
221                        return read(type, in);
222                }
223        }
224
225        /**
226         * Reads an object from the given file.
227         *
228         * @param path the path to read from.
229         * @return the deserialized object.
230         * @throws NullPointerException if the input stream {@code in} is {@code null}.
231         * @throws IOException if the object could not be read.
232         */
233        public Object read(final Path path) throws IOException {
234                return read(Object.class, path);
235        }
236
237        /**
238         * Reads an object from the given file.
239         *
240         * @param <T> the type of the read object
241         * @param file the file to read from.
242         * @param type the type of the read object.
243         * @return the deserialized object.
244         * @throws NullPointerException if the input stream {@code in} is {@code null}.
245         * @throws IOException if the object could not be read.
246         */
247        public <T> T read(final Class<T> type, final File file)
248                throws IOException
249        {
250                try (final FileInputStream in = new FileInputStream(file)) {
251                        return read(type, in);
252                }
253        }
254
255        /**
256         * Reads an object from the given file.
257         *
258         * @param file the file to read from.
259         * @return the deserialized object.
260         * @throws NullPointerException if the input stream {@code in} is {@code null}.
261         * @throws IOException if the object could not be read.
262         */
263        public Object read(final File file) throws IOException {
264                return read(Object.class, file);
265        }
266
267        /**
268         * Reads an object from the given input stream.
269         *
270         * @param <T> the type of the read object
271         * @param in the input stream to read from.
272         * @param type the type of the read object.
273         * @return the deserialized object.
274         * @throws NullPointerException if the input stream {@code in} is {@code null}.
275         * @throws IOException if the object could not be read.
276         */
277        public abstract <T> T read(final Class<T> type, final InputStream in)
278                throws IOException;
279
280        /**
281         * Reads an object from the given input stream.
282         *
283         * @param in the input stream to read from.
284         * @return the deserialized object.
285         * @throws NullPointerException if the input stream {@code in} is {@code null}.
286         * @throws IOException if the object could not be read.
287         */
288        public Object read(final InputStream in) throws IOException {
289                return read(Object.class, in);
290        }
291}