diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java index bfbe24aad5..89a97883c2 100644 --- a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java @@ -26,10 +26,7 @@ import java.net.URL; import java.net.URLConnection; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; -import java.nio.charset.Charset; -import java.nio.file.Files; import java.nio.file.NoSuchFileException; -import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.jar.JarEntry; @@ -323,39 +320,6 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { protected void customizeConnection(HttpURLConnection con) throws IOException { } - /** - * This implementation returns the contents of a file as a string using the - * system default Charset. Provided the resource exists and the context has - * access to it, the contents will be returned as a single string with line - * feed characters retained. - * @return the contents of the requested file as a {@code String}. - * @throws FileNotFoundException in the event the file path is invalid. - * @throws IOException if the file can not be read or cannot be serialzied. - */ - @Override - public String getContentAsString() throws IOException { - - if( !exists() ) { - throw new FileNotFoundException(getDescription() + " cannot be found."); - } - if ( !isReadable() ) { - throw new IOException(getDescription() + " cannot be opened for reading."); - } - return new String(Files.readAllBytes(Paths.get(getFile().getAbsolutePath())), Charset.defaultCharset()); - } - - @Override - public String getContentAsString(Charset charset) throws IOException { - - if( !exists() ) { - throw new FileNotFoundException(getDescription() + " cannot be found."); - } - if ( !isReadable() ) { - throw new IOException(getDescription() + " cannot be opened for reading."); - } - return new String(Files.readAllBytes(Paths.get(getFile().getAbsolutePath())), charset); - - } /** * Inner delegate class, avoiding a hard JBoss VFS API dependency at runtime. diff --git a/spring-core/src/main/java/org/springframework/core/io/ByteArrayResource.java b/spring-core/src/main/java/org/springframework/core/io/ByteArrayResource.java index c5989b8330..6e38d88812 100644 --- a/spring-core/src/main/java/org/springframework/core/io/ByteArrayResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/ByteArrayResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.core.io; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.Charset; import java.util.Arrays; import org.springframework.lang.Nullable; @@ -100,6 +101,19 @@ public class ByteArrayResource extends AbstractResource { return new ByteArrayInputStream(this.byteArray); } + @Override + public byte[] getContentAsByteArray() throws IOException { + int length = this.byteArray.length; + byte[] result = new byte[length]; + System.arraycopy(this.byteArray, 0, result, 0, length); + return result; + } + + @Override + public String getContentAsString(Charset charset) throws IOException { + return new String(this.byteArray, charset); + } + /** * This implementation returns a description that includes the passed-in * {@code description}, if any. diff --git a/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java b/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java index b5fda0a575..3db024f0c4 100644 --- a/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import java.net.URL; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.NoSuchFileException; @@ -196,6 +197,26 @@ public class FileSystemResource extends AbstractResource implements WritableReso } } + @Override + public byte[] getContentAsByteArray() throws IOException { + try { + return Files.readAllBytes(this.filePath); + } + catch (NoSuchFileException ex) { + throw new FileNotFoundException(ex.getMessage()); + } + } + + @Override + public String getContentAsString(Charset charset) throws IOException { + try { + return Files.readString(this.filePath, charset); + } + catch (NoSuchFileException ex) { + throw new FileNotFoundException(ex.getMessage()); + } + } + /** * This implementation checks whether the underlying file is marked as writable * (and corresponds to an actual file with content, not to a directory). diff --git a/spring-core/src/main/java/org/springframework/core/io/PathResource.java b/spring-core/src/main/java/org/springframework/core/io/PathResource.java index 6412f001a2..53debee25d 100644 --- a/spring-core/src/main/java/org/springframework/core/io/PathResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/PathResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import java.net.URI; import java.net.URL; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.OpenOption; @@ -141,6 +142,26 @@ public class PathResource extends AbstractResource implements WritableResource { return Files.newInputStream(this.path); } + @Override + public byte[] getContentAsByteArray() throws IOException { + try { + return Files.readAllBytes(this.path); + } + catch (NoSuchFileException ex) { + throw new FileNotFoundException(ex.getMessage()); + } + } + + @Override + public String getContentAsString(Charset charset) throws IOException { + try { + return Files.readString(this.path, charset); + } + catch (NoSuchFileException ex) { + throw new FileNotFoundException(ex.getMessage()); + } + } + /** * This implementation checks whether the underlying file is marked as writable * (and corresponds to an actual file with content, not to a directory). diff --git a/spring-core/src/main/java/org/springframework/core/io/Resource.java b/spring-core/src/main/java/org/springframework/core/io/Resource.java index 0d665d98f0..d652a3fb66 100644 --- a/spring-core/src/main/java/org/springframework/core/io/Resource.java +++ b/spring-core/src/main/java/org/springframework/core/io/Resource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,9 @@ package org.springframework.core.io; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.net.URI; import java.net.URL; import java.nio.channels.Channels; @@ -27,6 +27,7 @@ import java.nio.channels.ReadableByteChannel; import java.nio.charset.Charset; import org.springframework.lang.Nullable; +import org.springframework.util.FileCopyUtils; /** * Interface for a resource descriptor that abstracts from the actual @@ -179,40 +180,29 @@ public interface Resource extends InputStreamSource { String getDescription(); /** - * Return a {@link ReadableByteChannel}. - *
It is expected that each call creates a fresh channel. - *
The default implementation returns {@link Channels#newChannel(InputStream)} - * with the result of {@link #getInputStream()}. - * @return the byte channel for the underlying resource (must not be {@code null}) - * @throws java.io.FileNotFoundException if the underlying resource doesn't exist - * @throws IOException if the content channel could not be opened - * @since 5.0 - * @see #getInputStream() + * Return the contents of this resource as a byte array. + * @return the contents of this resource as byte array + * @throws java.io.FileNotFoundException if the resource cannot be resolved as + * absolute file path, i.e. if the resource is not available in a file system + * @throws IOException in case of general resolution/reading failures + * @since 6.0.5 */ - - /** - * Returns the contents of a file as a string using the system default Charset. - *
The default implementation returns a {@link Object#toString()} representation of the resource. - * @return the contents of the requested file as a {@code String}. - * @throws FileNotFoundException in the event the file path is invalid. - * @throws IOException if the file can not be read or cannot be accessed. - * @since 5.2.5 - */ - default String getContentAsString() throws IOException{ - return toString(); + default byte[] getContentAsByteArray() throws IOException { + return FileCopyUtils.copyToByteArray(getInputStream()); } /** - * Returns the contents of a file as a string using the specified Charset. - *
The default implementation returns a {@link Object#toString()} representation of the resource.
- * @param charset the {@code Charset} to use to deserialize the content. Defaults to system default.
- * @return the contents of the requested file as a {@code String}.
- * @throws FileNotFoundException in the event the file path is invalid.
- * @throws IOException if the file can not be read or cannot be accessed.
- * @since 5.2.5
+ * Returns the contents of this resource as a string, using the specified
+ * charset.
+ * @param charset the charset to use for decoding
+ * @return the contents of this resource as a {@code String}
+ * @throws java.io.FileNotFoundException if the resource cannot be resolved as
+ * absolute file path, i.e. if the resource is not available in a file system
+ * @throws IOException in case of general resolution/reading failures
+ * @since 6.0.5
*/
- default String getContentAsString(Charset charset) throws IOException{
- return toString();
+ default String getContentAsString(Charset charset) throws IOException {
+ return FileCopyUtils.copyToString(new InputStreamReader(getInputStream(), charset));
}
}
diff --git a/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java b/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java
index ed4eb169da..2d511515cc 100644
--- a/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java
+++ b/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2021 the original author or authors.
+ * Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -159,6 +159,27 @@ public class EncodedResource implements InputStreamSource {
return this.resource.getInputStream();
}
+ /**
+ * Returns the contents of the specified resource as a string, using the specified
+ * {@link #getCharset() Charset} or {@linkplain #getEncoding() encoding}
+ * (if any).
+ * @throws IOException if opening the resource failed
+ * @since 6.0.5
+ */
+ public String getContentAsString() throws IOException {
+ Charset charset;
+ if (this.charset != null) {
+ charset = this.charset;
+ }
+ else if (this.encoding != null) {
+ charset = Charset.forName(this.encoding);
+ }
+ else {
+ charset = Charset.defaultCharset();
+ }
+ return this.resource.getContentAsString(charset);
+ }
+
@Override
public boolean equals(@Nullable Object other) {
diff --git a/spring-core/src/test/java/org/springframework/core/io/ResourceTests.java b/spring-core/src/test/java/org/springframework/core/io/ResourceTests.java
index 70d7dbd534..7e4312c126 100644
--- a/spring-core/src/test/java/org/springframework/core/io/ResourceTests.java
+++ b/spring-core/src/test/java/org/springframework/core/io/ResourceTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +29,8 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
@@ -49,6 +51,7 @@ import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Unit tests for various {@link Resource} implementations.
@@ -69,6 +72,7 @@ class ResourceTests {
assertThat(resource.isReadable()).isTrue();
assertThat(resource.contentLength() > 0).isTrue();
assertThat(resource.lastModified() > 0).isTrue();
+ assertThat(resource.getContentAsByteArray()).containsExactly(Files.readAllBytes(Path.of(resource.getURI())));
}
@ParameterizedTest(name = "{index}: {0}")
@@ -113,24 +117,13 @@ class ResourceTests {
Resource relative4 = resource.createRelative("X.class");
assertThat(relative4.exists()).isFalse();
assertThat(relative4.isReadable()).isFalse();
+ assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(relative4::contentLength);
+ assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(relative4::lastModified);
+ assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(relative4::getInputStream);
+ assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(relative4::readableChannel);
+ assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(relative4::getContentAsByteArray);
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(
- relative4::contentLength);
- assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(
- relative4::lastModified);
- }
-
- @ParameterizedTest(name = "{index}: {0}")
- @MethodSource("resource")
- void loadingMissingResourceFails(Resource resource) {
- assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
- resource.createRelative("X").getInputStream());
- }
-
- @ParameterizedTest(name = "{index}: {0}")
- @MethodSource("resource")
- void readingMissingResourceFails(Resource resource) {
- assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
- resource.createRelative("X").readableChannel());
+ () -> relative4.getContentAsString(StandardCharsets.UTF_8));
}
private static Stream