Skip to content

Commit 4ae1709

Browse files
committed
relaxed generic Class declaration in HttpMessageConverter's canRead/canWrite/read signatures (SPR-6848)
1 parent 19cdd55 commit 4ae1709

13 files changed

+192
-183
lines changed

org.springframework.web/src/main/java/org/springframework/http/converter/AbstractHttpMessageConverter.java

Lines changed: 52 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2010 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,11 +34,12 @@
3434
/**
3535
* Abstract base class for most {@link HttpMessageConverter} implementations.
3636
*
37-
* <p>This base class adds support for setting supported {@code MediaTypes}, through the {@link
38-
* #setSupportedMediaTypes(List) supportedMediaTypes} bean property. It also adds support for {@code Content-Type} and
39-
* {@code Content-Length} when writing to output messages.
37+
* <p>This base class adds support for setting supported {@code MediaTypes}, through the
38+
* {@link #setSupportedMediaTypes(List) supportedMediaTypes} bean property. It also adds
39+
* support for {@code Content-Type} and {@code Content-Length} when writing to output messages.
4040
*
4141
* @author Arjen Poutsma
42+
* @author Juergen Hoeller
4243
* @since 3.0
4344
*/
4445
public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConverter<T> {
@@ -48,17 +49,16 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
4849

4950
private List<MediaType> supportedMediaTypes = Collections.emptyList();
5051

52+
5153
/**
5254
* Construct an {@code AbstractHttpMessageConverter} with no supported media types.
53-
*
5455
* @see #setSupportedMediaTypes
5556
*/
5657
protected AbstractHttpMessageConverter() {
5758
}
5859

5960
/**
6061
* Construct an {@code AbstractHttpMessageConverter} with one supported media type.
61-
*
6262
* @param supportedMediaType the supported media type
6363
*/
6464
protected AbstractHttpMessageConverter(MediaType supportedMediaType) {
@@ -67,14 +67,16 @@ protected AbstractHttpMessageConverter(MediaType supportedMediaType) {
6767

6868
/**
6969
* Construct an {@code AbstractHttpMessageConverter} with multiple supported media type.
70-
*
7170
* @param supportedMediaTypes the supported media types
7271
*/
7372
protected AbstractHttpMessageConverter(MediaType... supportedMediaTypes) {
7473
setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
7574
}
7675

77-
/** Set the list of {@link MediaType} objects supported by this converter. */
76+
77+
/**
78+
* Set the list of {@link MediaType} objects supported by this converter.
79+
*/
7880
public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) {
7981
Assert.notEmpty(supportedMediaTypes, "'supportedMediaTypes' must not be empty");
8082
this.supportedMediaTypes = new ArrayList<MediaType>(supportedMediaTypes);
@@ -84,21 +86,20 @@ public List<MediaType> getSupportedMediaTypes() {
8486
return Collections.unmodifiableList(this.supportedMediaTypes);
8587
}
8688

89+
8790
/**
8891
* {@inheritDoc}
89-
*
90-
* <p>This implementation checks if the given class is {@linkplain #supports(Class) supported}, and if the {@linkplain
91-
* #getSupportedMediaTypes() supported media types} {@linkplain MediaType#includes(MediaType) include} the given media
92-
* type.
92+
* <p>This implementation checks if the given class is {@linkplain #supports(Class) supported},
93+
* and if the {@linkplain #getSupportedMediaTypes() supported media types}
94+
* {@linkplain MediaType#includes(MediaType) include} the given media type.
9395
*/
9496
public boolean canRead(Class<?> clazz, MediaType mediaType) {
9597
return supports(clazz) && canRead(mediaType);
9698
}
9799

98100
/**
99-
* Returns true if any of the {@linkplain #setSupportedMediaTypes(List) supported media types} include the given media
100-
* type.
101-
*
101+
* Returns true if any of the {@linkplain #setSupportedMediaTypes(List) supported media types}
102+
* include the given media type.
102103
* @param mediaType the media type
103104
* @return true if the supported media types include the media type, or if the media type is {@code null}
104105
*/
@@ -116,10 +117,9 @@ protected boolean canRead(MediaType mediaType) {
116117

117118
/**
118119
* {@inheritDoc}
119-
*
120-
* <p>This implementation checks if the given class is {@linkplain #supports(Class) supported}, and if the {@linkplain
121-
* #getSupportedMediaTypes() supported media types} {@linkplain MediaType#includes(MediaType) include} the given media
122-
* type.
120+
* <p>This implementation checks if the given class is {@linkplain #supports(Class) supported},
121+
* and if the {@linkplain #getSupportedMediaTypes() supported media types}
122+
* {@linkplain MediaType#includes(MediaType) include} the given media type.
123123
*/
124124
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
125125
return supports(clazz) && canWrite(mediaType);
@@ -128,7 +128,6 @@ public boolean canWrite(Class<?> clazz, MediaType mediaType) {
128128
/**
129129
* Returns true if the given media type includes any of the
130130
* {@linkplain #setSupportedMediaTypes(List) supported media types}.
131-
*
132131
* @param mediaType the media type
133132
* @return true if the supported media types include the media type, or if the media type is {@code null}
134133
*/
@@ -144,45 +143,24 @@ protected boolean canWrite(MediaType mediaType) {
144143
return false;
145144
}
146145

147-
/**
148-
* Indicates whether the given class is supported by this converter.
149-
*
150-
* @param clazz the class to test for support
151-
* @return <code>true</code> if supported; <code>false</code> otherwise
152-
*/
153-
protected abstract boolean supports(Class<?> clazz);
154-
155146
/**
156147
* {@inheritDoc}
157-
*
158-
* <p>This implementation simple delegates to {@link #readInternal(Class, HttpInputMessage)}. Future implementations
159-
* might add some default behavior, however.
148+
* <p>This implementation simple delegates to {@link #readInternal(Class, HttpInputMessage)}.
149+
* Future implementations might add some default behavior, however.
160150
*/
161-
public final T read(Class<T> clazz, HttpInputMessage inputMessage) throws IOException {
151+
public final T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException {
162152
return readInternal(clazz, inputMessage);
163153
}
164154

165-
/**
166-
* Abstract template method that reads the actualy object. Invoked from {@link #read(Class, HttpInputMessage)}.
167-
*
168-
* @param clazz the type of object to return
169-
* @param inputMessage the HTTP input message to read from
170-
* @return the converted object
171-
* @throws IOException in case of I/O errors
172-
* @throws HttpMessageNotReadableException in case of conversion errors
173-
*/
174-
protected abstract T readInternal(Class<T> clazz, HttpInputMessage inputMessage)
175-
throws IOException, HttpMessageNotReadableException;
176-
177155
/**
178156
* {@inheritDoc}
179-
*
180-
* <p>This implementation delegates to {@link #getDefaultContentType(Object)} if a content type was not provided, calls
181-
* {@link #getContentLength}, and sets the corresponding headers on the output message. It then calls {@link
182-
* #writeInternal}.
157+
* <p>This implementation delegates to {@link #getDefaultContentType(Object)} if a content
158+
* type was not provided, calls {@link #getContentLength}, and sets the corresponding headers
159+
* on the output message. It then calls {@link #writeInternal}.
183160
*/
184161
public final void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
185162
throws IOException, HttpMessageNotWritableException {
163+
186164
HttpHeaders headers = outputMessage.getHeaders();
187165
if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
188166
contentType = getDefaultContentType(t);
@@ -199,12 +177,11 @@ public final void write(T t, MediaType contentType, HttpOutputMessage outputMess
199177
}
200178

201179
/**
202-
* Returns the default content type for the given type. Called when {@link #write} is invoked without a specified
203-
* content type parameter.
204-
*
205-
* <p>By default, this returns the first element of the {@link #setSupportedMediaTypes(List) supportedMediaTypes}
206-
* property, if any. Can be overriden in subclasses.
207-
*
180+
* Returns the default content type for the given type. Called when {@link #write}
181+
* is invoked without a specified content type parameter.
182+
* <p>By default, this returns the first element of the
183+
* {@link #setSupportedMediaTypes(List) supportedMediaTypes} property, if any.
184+
* Can be overridden in subclasses.
208185
* @param t the type to return the content type for
209186
* @return the content type, or <code>null</code> if not known
210187
*/
@@ -215,20 +192,36 @@ protected MediaType getDefaultContentType(T t) {
215192

216193
/**
217194
* Returns the content length for the given type.
218-
*
219-
* <p>By default, this returns {@code null}, meaning that the content length is unknown. Can be overriden in
220-
* subclasses.
221-
*
195+
* <p>By default, this returns {@code null}, meaning that the content length is unknown.
196+
* Can be overridden in subclasses.
222197
* @param t the type to return the content length for
223198
* @return the content length, or {@code null} if not known
224199
*/
225200
protected Long getContentLength(T t, MediaType contentType) {
226201
return null;
227202
}
228203

204+
205+
/**
206+
* Indicates whether the given class is supported by this converter.
207+
* @param clazz the class to test for support
208+
* @return <code>true</code> if supported; <code>false</code> otherwise
209+
*/
210+
protected abstract boolean supports(Class<?> clazz);
211+
212+
/**
213+
* Abstract template method that reads the actualy object. Invoked from {@link #read}.
214+
* @param clazz the type of object to return
215+
* @param inputMessage the HTTP input message to read from
216+
* @return the converted object
217+
* @throws IOException in case of I/O errors
218+
* @throws HttpMessageNotReadableException in case of conversion errors
219+
*/
220+
protected abstract T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage)
221+
throws IOException, HttpMessageNotReadableException;
222+
229223
/**
230224
* Abstract template method that writes the actual body. Invoked from {@link #write}.
231-
*
232225
* @param t the object to write to the output message
233226
* @param outputMessage the message to write to
234227
* @throws IOException in case of I/O errors

org.springframework.web/src/main/java/org/springframework/http/converter/BufferedImageHttpMessageConverter.java

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2010 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -62,37 +62,27 @@
6262
*/
6363
public class BufferedImageHttpMessageConverter implements HttpMessageConverter<BufferedImage> {
6464

65-
private List<MediaType> readableMediaTypes = new ArrayList<MediaType>();
65+
private final List<MediaType> readableMediaTypes = new ArrayList<MediaType>();
6666

6767
private MediaType defaultContentType;
6868

6969
private File cacheDir;
7070

71+
7172
public BufferedImageHttpMessageConverter() {
7273
String[] readerMediaTypes = ImageIO.getReaderMIMETypes();
7374
for (String mediaType : readerMediaTypes) {
74-
readableMediaTypes.add(MediaType.parseMediaType(mediaType));
75+
this.readableMediaTypes.add(MediaType.parseMediaType(mediaType));
7576
}
7677

7778
String[] writerMediaTypes = ImageIO.getWriterMIMETypes();
7879
if (writerMediaTypes.length > 0) {
79-
defaultContentType = MediaType.parseMediaType(writerMediaTypes[0]);
80+
this.defaultContentType = MediaType.parseMediaType(writerMediaTypes[0]);
8081
}
8182
}
8283

83-
/**
84-
* Returns the default {@code Content-Type} to be used for writing. Called when {@link #write} is invoked without a
85-
* specified content type parameter.
86-
*
87-
* @return the default content type
88-
*/
89-
public MediaType getDefaultContentType() {
90-
return defaultContentType;
91-
}
92-
9384
/**
9485
* Sets the default {@code Content-Type} to be used for writing.
95-
*
9686
* @throws IllegalArgumentException if the given content type is not supported by the Java Image I/O API
9787
*/
9888
public void setDefaultContentType(MediaType defaultContentType) {
@@ -106,20 +96,27 @@ public void setDefaultContentType(MediaType defaultContentType) {
10696
this.defaultContentType = defaultContentType;
10797
}
10898

109-
/** Sets the cache directory. If this property is set to an existing directory, this converter will cache image data. */
99+
/**
100+
* Returns the default {@code Content-Type} to be used for writing.
101+
* Called when {@link #write} is invoked without a specified content type parameter.
102+
*/
103+
public MediaType getDefaultContentType() {
104+
return this.defaultContentType;
105+
}
106+
107+
/**
108+
* Sets the cache directory. If this property is set to an existing directory,
109+
* this converter will cache image data.
110+
*/
110111
public void setCacheDir(File cacheDir) {
111112
Assert.notNull(cacheDir, "'cacheDir' must not be null");
112113
Assert.isTrue(cacheDir.isDirectory(), "'cacheDir' is not a directory");
113114
this.cacheDir = cacheDir;
114115
}
115116

117+
116118
public boolean canRead(Class<?> clazz, MediaType mediaType) {
117-
if (BufferedImage.class.equals(clazz)) {
118-
return isReadable(mediaType);
119-
}
120-
else {
121-
return false;
122-
}
119+
return (BufferedImage.class.equals(clazz) && isReadable(mediaType));
123120
}
124121

125122
private boolean isReadable(MediaType mediaType) {
@@ -131,12 +128,7 @@ private boolean isReadable(MediaType mediaType) {
131128
}
132129

133130
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
134-
if (BufferedImage.class.equals(clazz)) {
135-
return isWritable(mediaType);
136-
}
137-
else {
138-
return false;
139-
}
131+
return (BufferedImage.class.equals(clazz) && isWritable(mediaType));
140132
}
141133

142134
private boolean isWritable(MediaType mediaType) {
@@ -148,11 +140,12 @@ private boolean isWritable(MediaType mediaType) {
148140
}
149141

150142
public List<MediaType> getSupportedMediaTypes() {
151-
return Collections.unmodifiableList(readableMediaTypes);
143+
return Collections.unmodifiableList(this.readableMediaTypes);
152144
}
153145

154-
public BufferedImage read(Class<BufferedImage> clazz, HttpInputMessage inputMessage)
146+
public BufferedImage read(Class<? extends BufferedImage> clazz, HttpInputMessage inputMessage)
155147
throws IOException, HttpMessageNotReadableException {
148+
156149
ImageInputStream imageInputStream = null;
157150
ImageReader imageReader = null;
158151
try {
@@ -187,7 +180,7 @@ public BufferedImage read(Class<BufferedImage> clazz, HttpInputMessage inputMess
187180
}
188181

189182
private ImageInputStream createImageInputStream(InputStream is) throws IOException {
190-
if (cacheDir != null) {
183+
if (this.cacheDir != null) {
191184
return new FileCacheImageInputStream(is, cacheDir);
192185
}
193186
else {
@@ -197,6 +190,7 @@ private ImageInputStream createImageInputStream(InputStream is) throws IOExcepti
197190

198191
public void write(BufferedImage image, MediaType contentType, HttpOutputMessage outputMessage)
199192
throws IOException, HttpMessageNotWritableException {
193+
200194
if (contentType == null) {
201195
contentType = getDefaultContentType();
202196
}
@@ -236,27 +230,27 @@ public void write(BufferedImage image, MediaType contentType, HttpOutputMessage
236230
}
237231

238232
private ImageOutputStream createImageOutputStream(OutputStream os) throws IOException {
239-
if (cacheDir != null) {
240-
return new FileCacheImageOutputStream(os, cacheDir);
233+
if (this.cacheDir != null) {
234+
return new FileCacheImageOutputStream(os, this.cacheDir);
241235
}
242236
else {
243237
return new MemoryCacheImageOutputStream(os);
244238
}
245239
}
246240

241+
247242
/**
248243
* Template method that allows for manipulating the {@link ImageReadParam} before it is used to read an image.
249-
*
250244
* <p>Default implementation is empty.
251245
*/
252246
protected void process(ImageReadParam irp) {
253247
}
254248

255249
/**
256250
* Template method that allows for manipulating the {@link ImageWriteParam} before it is used to write an image.
257-
*
258251
* <p>Default implementation is empty.
259252
*/
260253
protected void process(ImageWriteParam iwp) {
261254
}
255+
262256
}

0 commit comments

Comments
 (0)