Skip to content

Commit 96b1dc9

Browse files
committed
ConversionService fully supports conversion from String to MediaType now (through 'valueOf'; SPR-7282); revised exception handling in ObjectToObjectConverter, avoiding InvocationTargetExceptions
1 parent 902938e commit 96b1dc9

File tree

4 files changed

+78
-76
lines changed

4 files changed

+78
-76
lines changed

org.springframework.core/src/main/java/org/springframework/core/convert/ConversionFailedException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public final class ConversionFailedException extends ConversionException {
4040
* @param cause the cause of the conversion failure
4141
*/
4242
public ConversionFailedException(TypeDescriptor sourceType, TypeDescriptor targetType, Object value, Throwable cause) {
43-
super("Unable to convert value " + value + " from type '" + sourceType.getName() +
43+
super("Unable to convert value \"" + value + "\" from type '" + sourceType.getName() +
4444
"' to type '" + targetType.getName() + "'", cause);
4545
this.sourceType = sourceType;
4646
this.targetType = targetType;

org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToObjectConverter.java

Lines changed: 17 additions & 27 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.
@@ -54,37 +54,27 @@ public Set<ConvertiblePair> getConvertibleTypes() {
5454
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
5555
Class<?> sourceClass = sourceType.getObjectType();
5656
Class<?> targetClass = targetType.getObjectType();
57-
Object target;
5857
Method method = getValueOfMethodOn(targetClass, sourceClass);
59-
if (method != null) {
60-
ReflectionUtils.makeAccessible(method);
61-
target = ReflectionUtils.invokeMethod(method, null, source);
62-
}
63-
else {
64-
Constructor<?> constructor = getConstructor(targetClass, sourceClass);
65-
if (constructor != null) {
66-
try {
67-
target = constructor.newInstance(source);
68-
}
69-
catch (IllegalArgumentException ex) {
70-
throw new ConversionFailedException(sourceType, targetType, source, ex);
71-
}
72-
catch (InstantiationException ex) {
73-
throw new ConversionFailedException(sourceType, targetType, source, ex);
74-
}
75-
catch (IllegalAccessException ex) {
76-
throw new ConversionFailedException(sourceType, targetType, source, ex);
77-
}
78-
catch (InvocationTargetException ex) {
79-
throw new ConversionFailedException(sourceType, targetType, source, ex);
80-
}
58+
try {
59+
if (method != null) {
60+
ReflectionUtils.makeAccessible(method);
61+
return method.invoke(null, source);
8162
}
8263
else {
83-
throw new IllegalStateException("No static valueOf(" + sourceClass.getName() +
84-
") method or Constructor(" + sourceClass.getName() + ") exists on " + targetClass.getName());
64+
Constructor<?> constructor = getConstructor(targetClass, sourceClass);
65+
if (constructor != null) {
66+
return constructor.newInstance(source);
67+
}
8568
}
8669
}
87-
return target;
70+
catch (InvocationTargetException ex) {
71+
throw new ConversionFailedException(sourceType, targetType, source, ex.getTargetException());
72+
}
73+
catch (Throwable ex) {
74+
throw new ConversionFailedException(sourceType, targetType, source, ex);
75+
}
76+
throw new IllegalStateException("No static valueOf(" + sourceClass.getName() +
77+
") method or Constructor(" + sourceClass.getName() + ") exists on " + targetClass.getName());
8878
}
8979

9080

org.springframework.web/src/main/java/org/springframework/http/MediaType.java

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@
3737
/**
3838
* Represents an Internet Media Type, as defined in the HTTP specification.
3939
*
40-
* <p>Consists of a {@linkplain #getType() type} and a {@linkplain #getSubtype() subtype}. Also has functionality to
41-
* parse media types from a string using {@link #parseMediaType(String)}, or multiple comma-separated media types using
42-
* {@link #parseMediaTypes(String)}.
40+
* <p>Consists of a {@linkplain #getType() type} and a {@linkplain #getSubtype() subtype}.
41+
* Also has functionality to parse media types from a string using {@link #parseMediaType(String)},
42+
* or multiple comma-separated media types using {@link #parseMediaTypes(String)}.
4343
*
4444
* @author Arjen Poutsma
4545
* @author Juergen Hoeller
46-
* @see <a href="http://tools.ietf.org/html/rfc2616#section-3.7">HTTP 1.1, section 3.7</a>
4746
* @since 3.0
47+
* @see <a href="http://tools.ietf.org/html/rfc2616#section-3.7">HTTP 1.1, section 3.7</a>
4848
*/
4949
public class MediaType implements Comparable<MediaType> {
5050

@@ -118,6 +118,7 @@ public class MediaType implements Comparable<MediaType> {
118118
* */
119119
public final static MediaType TEXT_XML;
120120

121+
121122
private static final BitSet TOKEN;
122123

123124
private static final String WILDCARD_TYPE = "*";
@@ -184,11 +185,10 @@ public class MediaType implements Comparable<MediaType> {
184185
TEXT_XML = new MediaType("text","xml");
185186
}
186187

188+
187189
/**
188190
* Create a new {@link MediaType} for the given primary type.
189-
*
190191
* <p>The {@linkplain #getSubtype() subtype} is set to <code>&#42;</code>, parameters empty.
191-
*
192192
* @param type the primary type
193193
* @throws IllegalArgumentException if any of the parameters contain illegal characters
194194
*/
@@ -197,8 +197,8 @@ public MediaType(String type) {
197197
}
198198

199199
/**
200-
* Create a new {@link MediaType} for the given primary type and subtype. <p>The parameters are empty.
201-
*
200+
* Create a new {@link MediaType} for the given primary type and subtype.
201+
* <p>The parameters are empty.
202202
* @param type the primary type
203203
* @param subtype the subtype
204204
* @throws IllegalArgumentException if any of the parameters contain illegal characters
@@ -209,7 +209,6 @@ public MediaType(String type, String subtype) {
209209

210210
/**
211211
* Create a new {@link MediaType} for the given type, subtype, and character set.
212-
*
213212
* @param type the primary type
214213
* @param subtype the subtype
215214
* @param charSet the character set
@@ -232,9 +231,8 @@ public MediaType(String type, String subtype, double qualityValue) {
232231
}
233232

234233
/**
235-
* Copy-constructor that copies the type and subtype of the given {@link MediaType}, and allows for different
236-
* parameter.
237-
*
234+
* Copy-constructor that copies the type and subtype of the given {@link MediaType},
235+
* and allows for different parameter.
238236
* @param other the other media type
239237
* @param parameters the parameters, may be <code>null</code>
240238
* @throws IllegalArgumentException if any of the parameters contain illegal characters
@@ -245,7 +243,6 @@ public MediaType(MediaType other, Map<String, String> parameters) {
245243

246244
/**
247245
* Create a new {@link MediaType} for the given type, subtype, and parameters.
248-
*
249246
* @param type the primary type
250247
* @param subtype the subtype
251248
* @param parameters the parameters, may be <code>null</code>
@@ -275,7 +272,6 @@ public MediaType(String type, String subtype, Map<String, String> parameters) {
275272

276273
/**
277274
* Checks the given token string for illegal characters, as defined in RFC 2616, section 2.2.
278-
*
279275
* @throws IllegalArgumentException in case of illegal characters
280276
* @see <a href="http://tools.ietf.org/html/rfc2616#section-2.2">HTTP 1.1, section 2.2</a>
281277
*/
@@ -295,7 +291,8 @@ private void checkParameters(String attribute, String value) {
295291
if (PARAM_QUALITY_FACTOR.equals(attribute)) {
296292
value = unquote(value);
297293
double d = Double.parseDouble(value);
298-
Assert.isTrue(d >= 0D && d <= 1D, "Invalid quality value \"" + value + "\": should be between 0.0 and 1.0");
294+
Assert.isTrue(d >= 0D && d <= 1D,
295+
"Invalid quality value \"" + value + "\": should be between 0.0 and 1.0");
299296
}
300297
else if (PARAM_CHARSET.equals(attribute)) {
301298
value = unquote(value);
@@ -317,24 +314,29 @@ private String unquote(String s) {
317314
return isQuotedString(s) ? s.substring(1, s.length() - 1) : s;
318315
}
319316

320-
/** Return the primary type. */
317+
/**
318+
* Return the primary type.
319+
*/
321320
public String getType() {
322321
return this.type;
323322
}
324323

325-
/** Indicate whether the {@linkplain #getType() type} is the wildcard character <code>&#42;</code> or not. */
324+
/**
325+
* Indicate whether the {@linkplain #getType() type} is the wildcard character <code>&#42;</code> or not.
326+
*/
326327
public boolean isWildcardType() {
327328
return WILDCARD_TYPE.equals(type);
328329
}
329330

330-
/** Return the subtype. */
331+
/**
332+
* Return the subtype.
333+
*/
331334
public String getSubtype() {
332335
return this.subtype;
333336
}
334337

335338
/**
336339
* Indicate whether the {@linkplain #getSubtype() subtype} is the wildcard character <code>&#42;</code> or not.
337-
*
338340
* @return whether the subtype is <code>&#42;</code>
339341
*/
340342
public boolean isWildcardSubtype() {
@@ -343,7 +345,6 @@ public boolean isWildcardSubtype() {
343345

344346
/**
345347
* Return the character set, as indicated by a <code>charset</code> parameter, if any.
346-
*
347348
* @return the character set; or <code>null</code> if not available
348349
*/
349350
public Charset getCharSet() {
@@ -352,8 +353,8 @@ public Charset getCharSet() {
352353
}
353354

354355
/**
355-
* Return the quality value, as indicated by a <code>q</code> parameter, if any. Defaults to <code>1.0</code>.
356-
*
356+
* Return the quality value, as indicated by a <code>q</code> parameter, if any.
357+
* Defaults to <code>1.0</code>.
357358
* @return the quality factory
358359
*/
359360
public double getQualityValue() {
@@ -363,7 +364,6 @@ public double getQualityValue() {
363364

364365
/**
365366
* Return a generic parameter value, given a parameter name.
366-
*
367367
* @param name the parameter name
368368
* @return the parameter value; or <code>null</code> if not present
369369
*/
@@ -373,10 +373,8 @@ public String getParameter(String name) {
373373

374374
/**
375375
* Indicate whether this {@link MediaType} includes the given media type.
376-
*
377376
* <p>For instance, {@code text/*} includes {@code text/plain}, {@code text/html}, and {@code application/*+xml}
378377
* includes {@code application/soap+xml}, etc. This method is non-symmetic.
379-
*
380378
* @param other the reference media type with which to compare
381379
* @return <code>true</code> if this media type includes the given media type; <code>false</code> otherwise
382380
*/
@@ -410,10 +408,8 @@ else if (this.type.equals(other.type)) {
410408

411409
/**
412410
* Indicate whether this {@link MediaType} is compatible with the given media type.
413-
*
414-
* <p>For instance, {@code text/*} is compatible with {@code text/plain}, {@code text/html}, and vice versa. In
415-
* effect, this method is similar to {@link #includes(MediaType)}, except that it's symmetric.
416-
*
411+
* <p>For instance, {@code text/*} is compatible with {@code text/plain}, {@code text/html}, and vice versa.
412+
* In effect, this method is similar to {@link #includes(MediaType)}, except that it's symmetric.
417413
* @param other the reference media type with which to compare
418414
* @return <code>true</code> if this media type is compatible with the given media type; <code>false</code> otherwise
419415
*/
@@ -449,7 +445,6 @@ else if (this.type.equals(other.type)) {
449445

450446
/**
451447
* Compares this {@link MediaType} to another alphabetically.
452-
*
453448
* @param other media type to compare to
454449
* @see #sortBySpecificity(List)
455450
*/
@@ -527,7 +522,7 @@ private void appendTo(StringBuilder builder) {
527522
appendTo(this.parameters, builder);
528523
}
529524

530-
private static void appendTo(Map<String, String> map, StringBuilder builder) {
525+
private void appendTo(Map<String, String> map, StringBuilder builder) {
531526
for (Map.Entry<String, String> entry : map.entrySet()) {
532527
builder.append(';');
533528
builder.append(entry.getKey());
@@ -536,9 +531,19 @@ private static void appendTo(Map<String, String> map, StringBuilder builder) {
536531
}
537532
}
538533

534+
535+
/**
536+
* Parse the given String value into a {@link MediaType} object,
537+
* with this method name following the 'valueOf' naming convention
538+
* (as supported by {@link org.springframework.core.convert.ConversionService}.
539+
* @see #parseMediaType(String)
540+
*/
541+
public static MediaType valueOf(String value) {
542+
return parseMediaType(value);
543+
}
544+
539545
/**
540546
* Parse the given String into a single {@link MediaType}.
541-
*
542547
* @param mediaType the string to parse
543548
* @return the media type
544549
* @throws IllegalArgumentException if the string cannot be parsed
@@ -581,9 +586,8 @@ public static MediaType parseMediaType(String mediaType) {
581586

582587

583588
/**
584-
* Parse the given, comma-seperated string into a list of {@link MediaType} objects. <p>This method can be used to
585-
* parse an Accept or Content-Type header.
586-
*
589+
* Parse the given, comma-seperated string into a list of {@link MediaType} objects.
590+
* <p>This method can be used to parse an Accept or Content-Type header.
587591
* @param mediaTypes the string to parse
588592
* @return the list of media types
589593
* @throws IllegalArgumentException if the string cannot be parsed
@@ -602,9 +606,7 @@ public static List<MediaType> parseMediaTypes(String mediaTypes) {
602606

603607
/**
604608
* Return a string representation of the given list of {@link MediaType} objects.
605-
*
606609
* <p>This method can be used to for an {@code Accept} or {@code Content-Type} header.
607-
*
608610
* @param mediaTypes the string to parse
609611
* @return the list of media types
610612
* @throws IllegalArgumentException if the String cannot be parsed
@@ -623,7 +625,6 @@ public static String toString(Collection<MediaType> mediaTypes) {
623625

624626
/**
625627
* Sorts the given list of {@link MediaType} objects by specificity.
626-
*
627628
* <p>Given two media types:
628629
* <ol>
629630
* <li>if either media type has a {@linkplain #isWildcardType() wildcard type}, then the media type without the
@@ -639,14 +640,12 @@ public static String toString(Collection<MediaType> mediaTypes) {
639640
* <li>if the two media types have a different amount of {@linkplain #getParameter(String) parameters}, then the
640641
* media type with the most parameters is ordered before the other.</li>
641642
* </ol>
642-
*
643643
* <p>For example:
644644
* <blockquote>audio/basic &lt; audio/* &lt; *&#047;*</blockquote>
645645
* <blockquote>audio/* &lt; audio/*;q=0.7; audio/*;q=0.3</blockquote>
646646
* <blockquote>audio/basic;level=1 &lt; audio/basic</blockquote>
647647
* <blockquote>audio/basic == text/html</blockquote>
648648
* <blockquote>audio/basic == audio/wave</blockquote>
649-
*
650649
* @param mediaTypes the list of media types to be sorted
651650
* @see <a href="http://tools.ietf.org/html/rfc2616#section-14.1">HTTP 1.1, section 14.1</a>
652651
*/
@@ -659,7 +658,6 @@ public static void sortBySpecificity(List<MediaType> mediaTypes) {
659658

660659
/**
661660
* Sorts the given list of {@link MediaType} objects by quality value.
662-
*
663661
* <p>Given two media types:
664662
* <ol>
665663
* <li>if the two media types have different {@linkplain #getQualityValue() quality value}, then the media type
@@ -675,7 +673,6 @@ public static void sortBySpecificity(List<MediaType> mediaTypes) {
675673
* <li>if the two media types have a different amount of {@linkplain #getParameter(String) parameters}, then the
676674
* media type with the most parameters is ordered before the other.</li>
677675
* </ol>
678-
*
679676
* @param mediaTypes the list of media types to be sorted
680677
* @see #getQualityValue()
681678
*/
@@ -686,6 +683,7 @@ public static void sortByQualityValue(List<MediaType> mediaTypes) {
686683
}
687684
}
688685

686+
689687
static final Comparator<MediaType> SPECIFICITY_COMPARATOR = new Comparator<MediaType>() {
690688

691689
public int compare(MediaType mediaType1, MediaType mediaType2) {
@@ -714,7 +712,8 @@ else if (!mediaType1.getSubtype().equals(mediaType2.getSubtype())) { // audio/ba
714712
int qualityComparison = Double.compare(quality2, quality1);
715713
if (qualityComparison != 0) {
716714
return qualityComparison; // audio/*;q=0.7 < audio/*;q=0.3
717-
} else {
715+
}
716+
else {
718717
int paramsSize1 = mediaType1.parameters.size();
719718
int paramsSize2 = mediaType2.parameters.size();
720719
return (paramsSize2 < paramsSize1 ? -1 : (paramsSize2 == paramsSize1 ? 0 : 1)); // audio/basic;level=1 < audio/basic
@@ -724,6 +723,7 @@ else if (!mediaType1.getSubtype().equals(mediaType2.getSubtype())) { // audio/ba
724723
}
725724
};
726725

726+
727727
static final Comparator<MediaType> QUALITY_VALUE_COMPARATOR = new Comparator<MediaType>() {
728728

729729
public int compare(MediaType mediaType1, MediaType mediaType2) {
@@ -751,12 +751,14 @@ else if (mediaType2.isWildcardSubtype() && !mediaType1.isWildcardSubtype()) { //
751751
}
752752
else if (!mediaType1.getSubtype().equals(mediaType2.getSubtype())) { // audio/basic == audio/wave
753753
return 0;
754-
} else {
754+
}
755+
else {
755756
int paramsSize1 = mediaType1.parameters.size();
756757
int paramsSize2 = mediaType2.parameters.size();
757758
return (paramsSize2 < paramsSize1 ? -1 : (paramsSize2 == paramsSize1 ? 0 : 1)); // audio/basic;level=1 < audio/basic
758759
}
759760
}
760761
}
761762
};
763+
762764
}

0 commit comments

Comments
 (0)