001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.io.support; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.InputStreamReader; 022import java.io.Reader; 023import java.nio.charset.Charset; 024 025import org.springframework.core.io.InputStreamSource; 026import org.springframework.core.io.Resource; 027import org.springframework.util.Assert; 028import org.springframework.util.ObjectUtils; 029 030/** 031 * Holder that combines a {@link Resource} descriptor with a specific encoding 032 * or {@code Charset} to be used for reading from the resource. 033 * 034 * <p>Used as an argument for operations that support reading content with 035 * a specific encoding, typically via a {@code java.io.Reader}. 036 * 037 * @author Juergen Hoeller 038 * @author Sam Brannen 039 * @since 1.2.6 040 * @see Resource#getInputStream() 041 * @see java.io.Reader 042 * @see java.nio.charset.Charset 043 */ 044public class EncodedResource implements InputStreamSource { 045 046 private final Resource resource; 047 048 private final String encoding; 049 050 private final Charset charset; 051 052 053 /** 054 * Create a new {@code EncodedResource} for the given {@code Resource}, 055 * not specifying an explicit encoding or {@code Charset}. 056 * @param resource the {@code Resource} to hold (never {@code null}) 057 */ 058 public EncodedResource(Resource resource) { 059 this(resource, null, null); 060 } 061 062 /** 063 * Create a new {@code EncodedResource} for the given {@code Resource}, 064 * using the specified {@code encoding}. 065 * @param resource the {@code Resource} to hold (never {@code null}) 066 * @param encoding the encoding to use for reading from the resource 067 */ 068 public EncodedResource(Resource resource, String encoding) { 069 this(resource, encoding, null); 070 } 071 072 /** 073 * Create a new {@code EncodedResource} for the given {@code Resource}, 074 * using the specified {@code Charset}. 075 * @param resource the {@code Resource} to hold (never {@code null}) 076 * @param charset the {@code Charset} to use for reading from the resource 077 */ 078 public EncodedResource(Resource resource, Charset charset) { 079 this(resource, null, charset); 080 } 081 082 private EncodedResource(Resource resource, String encoding, Charset charset) { 083 super(); 084 Assert.notNull(resource, "Resource must not be null"); 085 this.resource = resource; 086 this.encoding = encoding; 087 this.charset = charset; 088 } 089 090 091 /** 092 * Return the {@code Resource} held by this {@code EncodedResource}. 093 */ 094 public final Resource getResource() { 095 return this.resource; 096 } 097 098 /** 099 * Return the encoding to use for reading from the {@linkplain #getResource() resource}, 100 * or {@code null} if none specified. 101 */ 102 public final String getEncoding() { 103 return this.encoding; 104 } 105 106 /** 107 * Return the {@code Charset} to use for reading from the {@linkplain #getResource() resource}, 108 * or {@code null} if none specified. 109 */ 110 public final Charset getCharset() { 111 return this.charset; 112 } 113 114 /** 115 * Determine whether a {@link Reader} is required as opposed to an {@link InputStream}, 116 * i.e. whether an {@linkplain #getEncoding() encoding} or a {@link #getCharset() Charset} 117 * has been specified. 118 * @see #getReader() 119 * @see #getInputStream() 120 */ 121 public boolean requiresReader() { 122 return (this.encoding != null || this.charset != null); 123 } 124 125 /** 126 * Open a {@code java.io.Reader} for the specified resource, using the specified 127 * {@link #getCharset() Charset} or {@linkplain #getEncoding() encoding} 128 * (if any). 129 * @throws IOException if opening the Reader failed 130 * @see #requiresReader() 131 * @see #getInputStream() 132 */ 133 public Reader getReader() throws IOException { 134 if (this.charset != null) { 135 return new InputStreamReader(this.resource.getInputStream(), this.charset); 136 } 137 else if (this.encoding != null) { 138 return new InputStreamReader(this.resource.getInputStream(), this.encoding); 139 } 140 else { 141 return new InputStreamReader(this.resource.getInputStream()); 142 } 143 } 144 145 /** 146 * Open an {@code InputStream} for the specified resource, ignoring any specified 147 * {@link #getCharset() Charset} or {@linkplain #getEncoding() encoding}. 148 * @throws IOException if opening the InputStream failed 149 * @see #requiresReader() 150 * @see #getReader() 151 */ 152 @Override 153 public InputStream getInputStream() throws IOException { 154 return this.resource.getInputStream(); 155 } 156 157 158 @Override 159 public boolean equals(Object other) { 160 if (this == other) { 161 return true; 162 } 163 if (!(other instanceof EncodedResource)) { 164 return false; 165 } 166 EncodedResource otherResource = (EncodedResource) other; 167 return (this.resource.equals(otherResource.resource) && 168 ObjectUtils.nullSafeEquals(this.charset, otherResource.charset) && 169 ObjectUtils.nullSafeEquals(this.encoding, otherResource.encoding)); 170 } 171 172 @Override 173 public int hashCode() { 174 return this.resource.hashCode(); 175 } 176 177 @Override 178 public String toString() { 179 return this.resource.toString(); 180 } 181 182}