Spring 4.3 controller戻り値変換
7457 ワード
AbstractMessageConverterMethodProcessor
の方法protected void writeWithMessageConverters(T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
HttpServletRequest request = inputMessage.getServletRequest();
List requestedMediaTypes = getAcceptableMediaTypes(request);
List producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
if (outputValue != null && producibleMediaTypes.isEmpty()) {
throw new IllegalArgumentException("No converter found for return value of type: " + valueType);
}
Set compatibleMediaTypes = new LinkedHashSet();
for (MediaType requestedType : requestedMediaTypes) {
for (MediaType producibleType : producibleMediaTypes) {
if (requestedType.isCompatibleWith(producibleType)) {
compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
if (compatibleMediaTypes.isEmpty()) {
if (outputValue != null) {
throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
}
return;
}
List mediaTypes = new ArrayList(compatibleMediaTypes);
MediaType.sortBySpecificityAndQuality(mediaTypes);
MediaType selectedMediaType = null;
for (MediaType mediaType : mediaTypes) {
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
}
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter> messageConverter : this.messageConverters) {
if (messageConverter instanceof GenericHttpMessageConverter) {
if (((GenericHttpMessageConverter) messageConverter).canWrite(
declaredType, valueType, selectedMediaType)) {
outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
(Class extends HttpMessageConverter>>) messageConverter.getClass(),
inputMessage, outputMessage);
if (outputValue != null) {
addContentDispositionHeader(inputMessage, outputMessage);
((GenericHttpMessageConverter) messageConverter).write(
outputValue, declaredType, selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) {
logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
"\" using [" + messageConverter + "]");
}
}
return;
}
}
else if (messageConverter.canWrite(valueType, selectedMediaType)) {
outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
(Class extends HttpMessageConverter>>) messageConverter.getClass(),
inputMessage, outputMessage);
if (outputValue != null) {
addContentDispositionHeader(inputMessage, outputMessage);
((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) {
logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
"\" using [" + messageConverter + "]");
}
}
return;
}
}
}
if (outputValue != null) {
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}
まず要求からrequestedMediaTypesを取得して、現地のproducible MediaTypesと比較します.例えば、appication/jsonは、主なタイプはappicationで、サブタイプはjsonです.要求されたメディアタイプと生成可能なメディアタイプが、メインタイプとサブタイプが一致する場合(ワイルドカードが+などの場合、比較プロセスが複雑で詳細はMiMeType、public boottible With)、それをcomptible MediaTypesに入れます.メディアタイプにマッチしていない場合は、例外を投げます.
また、comptible MediaTypeからselectedMediaTypeを選択します.comptible MediaTypesを一つずつフィルタします.具体的なタイプ(ワイルドカードがない)なら、このタイプが選ばれます.このタイプがMediaType.ALL(*/*)またはaplicationであれば、aplication/octet-stream(Media.APPLICATIONuOCTETUSTREAM).
List> messageConverters
は、それぞれのboolean canWrite(Type type, Class> clazz, MediaType mediaType);
方法を実行し、もしtrueに戻るならば、それを用いて実行する.現在端の要求(通常はajax)にrequest Headerがある場合、selectedMediaTypeとして機能します.先端の要求にheaderが指定されていない場合、aplicationはselecteMediaTypeとして選択されます.