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として選択されます.