001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package dev.metaschema.databind.io;
007
008import java.io.File;
009import java.io.IOException;
010import java.io.InputStream;
011import java.io.InputStreamReader;
012import java.io.Reader;
013import java.net.URI;
014import java.net.URISyntaxException;
015import java.net.URL;
016import java.nio.charset.StandardCharsets;
017import java.nio.file.Files;
018import java.nio.file.Path;
019
020import dev.metaschema.core.configuration.IConfiguration;
021import dev.metaschema.core.configuration.IMutableConfiguration;
022import dev.metaschema.core.metapath.item.node.INodeItem;
023import dev.metaschema.core.model.IBoundObject;
024import dev.metaschema.core.model.constraint.IConstraintValidationHandler;
025import dev.metaschema.core.util.ObjectUtils;
026import edu.umd.cs.findbugs.annotations.NonNull;
027
028/**
029 * Implementations of this interface are able to read structured data into a
030 * bound object instance of the parameterized type.
031 *
032 * @param <CLASS>
033 *          the Java type into which data can be read
034 */
035public interface IDeserializer<CLASS extends IBoundObject> extends IMutableConfiguration<DeserializationFeature<?>> {
036
037  @Override
038  IDeserializer<CLASS> enableFeature(DeserializationFeature<?> feature);
039
040  @Override
041  IDeserializer<CLASS> disableFeature(DeserializationFeature<?> feature);
042
043  @Override
044  IDeserializer<CLASS> applyConfiguration(IConfiguration<DeserializationFeature<?>> other);
045
046  @Override
047  IDeserializer<CLASS> set(DeserializationFeature<?> feature, Object value);
048
049  /**
050   * Determine if the serializer is performing validation.
051   *
052   * @return {@code true} if the serializer is performing content validation, or
053   *         {@code false} otherwise
054   */
055  default boolean isValidating() {
056    return isFeatureEnabled(DeserializationFeature.DESERIALIZE_VALIDATE_CONSTRAINTS);
057  }
058
059  /**
060   * Get the constraint validation handler configured for this deserializer, which
061   * will be used to validate loaded data.
062   *
063   * @return the validation handler
064   */
065  @NonNull
066  IConstraintValidationHandler getConstraintValidationHandler();
067
068  /**
069   * Set the constraint violation handler for constraint validation.
070   *
071   * @param handler
072   *          the handler to use
073   */
074  void setConstraintValidationHandler(@NonNull IConstraintValidationHandler handler);
075
076  /**
077   * Read data from the {@link InputStream} into a bound class instance.
078   *
079   * @param is
080   *          the input stream to read from
081   * @param documentUri
082   *          the URI of the document to read from
083   * @return the instance data
084   * @throws IOException
085   *           if an error occurred while reading data from the stream
086   */
087  @NonNull
088  default CLASS deserialize(@NonNull InputStream is, @NonNull URI documentUri) throws IOException {
089    return deserialize(new InputStreamReader(is, StandardCharsets.UTF_8), documentUri);
090  }
091
092  /**
093   * Read data from the {@link Path} into a bound class instance.
094   *
095   * @param path
096   *          the file to read from
097   * @return the instance data
098   * @throws IOException
099   *           if an error occurred while writing data to the file indicated by
100   *           the {@code path} parameter
101   */
102  @NonNull
103  default CLASS deserialize(@NonNull Path path) throws IOException {
104    try (Reader reader = ObjectUtils.notNull(Files.newBufferedReader(path, StandardCharsets.UTF_8))) {
105      return deserialize(reader, ObjectUtils.notNull(path.toUri()));
106    }
107  }
108
109  /**
110   * Read data from the {@link File} into a bound class instance.
111   *
112   * @param file
113   *          the file to read from
114   * @return the instance data
115   * @throws IOException
116   *           if an error occurred while reading data from the stream
117   */
118  @NonNull
119  default CLASS deserialize(@NonNull File file) throws IOException {
120    return deserialize(ObjectUtils.notNull(file.toPath()));
121  }
122
123  /**
124   * Read data from the remote resource into a bound class instance.
125   *
126   *
127   * @param url
128   *          the remote resource to read from
129   * @return the instance data
130   * @throws IOException
131   *           if an error occurred while reading data from the stream
132   * @throws URISyntaxException
133   *           if the provided URL is not formatted strictly according to to
134   *           RFC2396 and cannot be converted to a URI.
135   */
136  @NonNull
137  default CLASS deserialize(@NonNull URL url) throws IOException, URISyntaxException {
138    try (InputStream in = ObjectUtils.notNull(url.openStream())) {
139      return deserialize(in, ObjectUtils.notNull(url.toURI()));
140    }
141  }
142
143  /**
144   * Read data from the {@link Reader} into a bound class instance.
145   *
146   *
147   * @param reader
148   *          the reader to read from
149   * @param documentUri
150   *          the URI of the document to read from
151   * @return the instance data
152   * @throws IOException
153   *           if an error occurred while reading data from the stream
154   */
155  @NonNull
156  default CLASS deserialize(@NonNull Reader reader, @NonNull URI documentUri) throws IOException {
157    return deserializeToValue(reader, documentUri);
158  }
159
160  /**
161   * Read data from the {@link Reader} into a node item instance.
162   *
163   * @param is
164   *          the input stream to read from
165   * @param documentUri
166   *          the URI of the document to read from
167   * @return a new node item
168   * @throws IOException
169   *           if an error occurred while reading data from the stream
170   */
171  @NonNull
172  default INodeItem deserializeToNodeItem(@NonNull InputStream is, @NonNull URI documentUri)
173      throws IOException {
174    return deserializeToNodeItem(new InputStreamReader(is, StandardCharsets.UTF_8), documentUri);
175  }
176
177  /**
178   * Read data from the {@link Reader} into a node item instance.
179   *
180   * @param reader
181   *          the reader to read from
182   * @param documentUri
183   *          the URI of the document to read from
184   * @return a new node item
185   * @throws IOException
186   *           if an error occurred while reading data from the stream
187   */
188  @NonNull
189  INodeItem deserializeToNodeItem(@NonNull Reader reader, @NonNull URI documentUri) throws IOException;
190
191  /**
192   * Read data from the {@link Reader} into a node item instance.
193   *
194   * @param reader
195   *          the reader to read from
196   * @param documentUri
197   *          the URI of the document to read from
198   * @return a new node item
199   * @throws IOException
200   *           if an error occurred while reading data from the stream
201   */
202  @NonNull
203  CLASS deserializeToValue(@NonNull Reader reader, @NonNull URI documentUri) throws IOException;
204}