This is an automated email from the ASF dual-hosted git repository. ahuber pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/master by this push: new e0d5938510 ISIS-3300: support file i/o for Blob and Clob (convenience) e0d5938510 is described below commit e0d59385101b09d1c452c2124a29eca9ef0a98b0 Author: Andi Huber <ahu...@apache.org> AuthorDate: Thu Dec 1 18:41:23 2022 +0100 ISIS-3300: support file i/o for Blob and Clob (convenience) --- .../org/apache/causeway/applib/value/Blob.java | 56 ++++++++++++++++++++-- .../org/apache/causeway/applib/value/Clob.java | 54 +++++++++++++++++++++ .../domainmodel/MetaModelRegressionTest.java | 18 +++---- 3 files changed, 113 insertions(+), 15 deletions(-) diff --git a/api/applib/src/main/java/org/apache/causeway/applib/value/Blob.java b/api/applib/src/main/java/org/apache/causeway/applib/value/Blob.java index 2acada6c29..794df8b10c 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/value/Blob.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/value/Blob.java @@ -20,6 +20,9 @@ package org.apache.causeway.applib.value; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -36,11 +39,14 @@ import javax.inject.Named; import javax.xml.bind.annotation.adapters.XmlAdapter; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import org.springframework.lang.Nullable; + import org.apache.causeway.applib.CausewayModuleApplib; import org.apache.causeway.applib.annotation.Value; import org.apache.causeway.applib.jaxb.PrimitiveJaxbAdapters; import org.apache.causeway.applib.util.ZipReader; import org.apache.causeway.applib.util.ZipWriter; +import org.apache.causeway.commons.functional.Try; import org.apache.causeway.commons.internal.base._Bytes; import org.apache.causeway.commons.internal.base._Strings; import org.apache.causeway.commons.internal.exceptions._Exceptions; @@ -113,6 +119,28 @@ public final class Blob implements NamedWithMimeType { return new Blob(fileName, mimeType.getMimeType(), content); } + /** + * Returns a new {@link Blob} of given {@code name}, {@code mimeType} and content from {@code file}, + * wrapped with a {@link Try}. + * <p> + * {@code name} may or may not include the desired filename extension, it + * is guaranteed, that the resulting {@link Blob} has the appropriate extension + * as constraint by the given {@code mimeType}. + * <p> + * For more fine-grained control use one of the {@link Blob} constructors directly. + * @param name - may or may not include the desired filename extension + * @param mimeType + * @param file - the file to be opened for reading + * @return new {@link Blob} + */ + public static Try<Blob> tryRead(final String name, final CommonMimeType mimeType, final File file) { + return Try.call(()->{ + try(val fis = new FileInputStream(file)){ + return Blob.of(name, mimeType, _Bytes.ofKeepOpen(fis)); + } + }); + } + // -- private final MimeType mimeType; @@ -167,10 +195,9 @@ public final class Blob implements NamedWithMimeType { /** * Does not close the OutputStream. - * @param os - * @throws IOException */ - public void writeBytesTo(final OutputStream os) throws IOException { + @SneakyThrows + public void writeBytesTo(final @Nullable OutputStream os) { if(os==null) { return; } @@ -179,12 +206,33 @@ public final class Blob implements NamedWithMimeType { } } + /** + * Writes this {@link Blob} to the file represented by + * the specified <code>File</code> object. + * <p> + * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a <code>FileNotFoundException</code> is thrown. + * + * @param file the file to be opened for writing; if <code>null</code> this method does nothing + * @see java.io.FileOutputStream + */ + @SneakyThrows + public void writeTo(final @Nullable File file) { + if(file==null) { + return; // just ignore + } + try(val os = new FileOutputStream(file)){ + writeBytesTo(os); + } + } + /** * The {@link InputStream} involved is closed after consumption. * @param consumer * @throws IOException */ - public void consume(final Consumer<InputStream> consumer) throws IOException { + public void consume(final @NonNull Consumer<InputStream> consumer) throws IOException { // null to empty val bytes = Optional.ofNullable(getBytes()) .orElse(new byte[0]); diff --git a/api/applib/src/main/java/org/apache/causeway/applib/value/Clob.java b/api/applib/src/main/java/org/apache/causeway/applib/value/Clob.java index 80a047ab76..5e7cb3f9d7 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/value/Clob.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/value/Clob.java @@ -18,7 +18,11 @@ */ package org.apache.causeway.applib.value; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.StringWriter; import java.io.Writer; import java.nio.charset.Charset; @@ -31,9 +35,12 @@ import javax.inject.Named; import javax.xml.bind.annotation.adapters.XmlAdapter; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import org.springframework.lang.Nullable; + import org.apache.causeway.applib.CausewayModuleApplib; import org.apache.causeway.applib.annotation.Value; import org.apache.causeway.applib.jaxb.PrimitiveJaxbAdapters; +import org.apache.causeway.commons.functional.Try; import org.apache.causeway.commons.internal.base._Strings; import lombok.NonNull; @@ -107,6 +114,30 @@ public final class Clob implements NamedWithMimeType { return new Clob(fileName, mimeType.getMimeType(), content); } + /** + * Returns a new {@link Clob} of given {@code name}, {@code mimeType} and content from {@code file}, + * wrapped with a {@link Try}. + * <p> + * {@code name} may or may not include the desired filename extension, it + * is guaranteed, that the resulting {@link Clob} has the appropriate extension + * as constraint by the given {@code mimeType}. + * <p> + * For more fine-grained control use one of the {@link Clob} constructors directly. + * @param name - may or may not include the desired filename extension + * @param mimeType + * @param file - the file to be opened for reading + * @param charset - {@link Charset} to use for reading given file + * @return new {@link Clob} + */ + public static Try<Clob> tryRead(final String name, final CommonMimeType mimeType, final File file, + final @NonNull Charset charset) { + return Try.call(()->{ + try(val fis = new FileInputStream(file)){ + return Clob.of(name, mimeType, _Strings.read(fis, charset)); + } + }); + } + // -- public Clob(final String name, final String primaryType, final String subType, final char[] chars) { @@ -173,6 +204,29 @@ public final class Clob implements NamedWithMimeType { } } + /** + * Writes this {@link Clob} to the file represented by + * the specified <code>File</code> object. + * <p> + * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a <code>FileNotFoundException</code> is thrown. + * + * @param file the file to be opened for writing; if <code>null</code> this method does nothing + * @param charset - {@link Charset} to use for writing to given file + * @see java.io.FileOutputStream + * @see java.io.OutputStreamWriter + */ + @SneakyThrows + public void writeTo(final @Nullable File file, final @NonNull Charset charset) { + if(file==null) { + return; // just ignore + } + try(val os = new FileOutputStream(file)){ + writeCharsTo(new OutputStreamWriter(os, StandardCharsets.UTF_8)); + } + } + @SneakyThrows public String asString() { val sw = new StringWriter(); diff --git a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/MetaModelRegressionTest.java b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/MetaModelRegressionTest.java index 609c515296..90a9ef0825 100644 --- a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/MetaModelRegressionTest.java +++ b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/MetaModelRegressionTest.java @@ -18,7 +18,6 @@ */ package org.apache.causeway.testdomain.domainmodel; -import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; @@ -44,7 +43,6 @@ import org.apache.causeway.testdomain.conf.Configuration_headless; import org.apache.causeway.testdomain.model.good.Configuration_usingValidDomain; import lombok.SneakyThrows; -import lombok.val; @SpringBootTest( classes = { @@ -81,17 +79,15 @@ class MetaModelRegressionTest { // disable if rename, as the .zip file needs to be updated. // Assumptions.assumeThat(getClass().getName()).contains("causeway"); - Blob metaModelZip = factoryService.mixin(MetaModelServiceMenu.downloadMetaModelXml.class, - metaModelServiceMenu).act("metamodel.xml", namespaces(), true); - val xml = asXml(metaModelZip); + final Blob metaModelZip = factoryService + .mixin(MetaModelServiceMenu.downloadMetaModelXml.class, metaModelServiceMenu) + .act("metamodel.xml", namespaces(), true); + final String xml = metaModelZip + .unZip(CommonMimeType.XML) + .toClob(StandardCharsets.UTF_8) + .asString(); Approvals.verify(xml, options()); - - } - - private static String asXml(final Blob zip) throws IOException { - val clob = zip.unZip(CommonMimeType.XML).toClob(StandardCharsets.UTF_8); - return clob.asString(); } private Options options() {