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