org.springframework.http.converter.FormHttpMessageConverterTests.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.http.converter.FormHttpMessageConverterTests.java

Source

/*
 * Copyright 2002-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.http.converter;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.junit.Test;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.MockHttpInputMessage;
import org.springframework.http.MockHttpOutputMessage;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.BDDMockito.never;
import static org.mockito.BDDMockito.verify;

/**
 * @author Arjen Poutsma
 * @author Rossen Stoyanchev
 */
public class FormHttpMessageConverterTests {

    private final FormHttpMessageConverter converter = new AllEncompassingFormHttpMessageConverter();

    @Test
    public void canRead() {
        assertTrue(
                this.converter.canRead(MultiValueMap.class, new MediaType("application", "x-www-form-urlencoded")));
        assertFalse(this.converter.canRead(MultiValueMap.class, new MediaType("multipart", "form-data")));
    }

    @Test
    public void canWrite() {
        assertTrue(this.converter.canWrite(MultiValueMap.class,
                new MediaType("application", "x-www-form-urlencoded")));
        assertTrue(this.converter.canWrite(MultiValueMap.class, new MediaType("multipart", "form-data")));
        assertTrue(this.converter.canWrite(MultiValueMap.class,
                new MediaType("multipart", "form-data", StandardCharsets.UTF_8)));
        assertTrue(this.converter.canWrite(MultiValueMap.class, MediaType.ALL));
    }

    @Test
    public void readForm() throws Exception {
        String body = "name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3";
        MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(StandardCharsets.ISO_8859_1));
        inputMessage.getHeaders()
                .setContentType(new MediaType("application", "x-www-form-urlencoded", StandardCharsets.ISO_8859_1));
        MultiValueMap<String, String> result = this.converter.read(null, inputMessage);

        assertEquals("Invalid result", 3, result.size());
        assertEquals("Invalid result", "value 1", result.getFirst("name 1"));
        List<String> values = result.get("name 2");
        assertEquals("Invalid result", 2, values.size());
        assertEquals("Invalid result", "value 2+1", values.get(0));
        assertEquals("Invalid result", "value 2+2", values.get(1));
        assertNull("Invalid result", result.getFirst("name 3"));
    }

    @Test
    public void writeForm() throws IOException {
        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.set("name 1", "value 1");
        body.add("name 2", "value 2+1");
        body.add("name 2", "value 2+2");
        body.add("name 3", null);
        MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
        this.converter.write(body, MediaType.APPLICATION_FORM_URLENCODED, outputMessage);

        assertEquals("Invalid result", "name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3",
                outputMessage.getBodyAsString(StandardCharsets.UTF_8));
        assertEquals("Invalid content-type", new MediaType("application", "x-www-form-urlencoded"),
                outputMessage.getHeaders().getContentType());
        assertEquals("Invalid content-length", outputMessage.getBodyAsBytes().length,
                outputMessage.getHeaders().getContentLength());
    }

    @Test
    public void writeMultipart() throws Exception {
        MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
        parts.add("name 1", "value 1");
        parts.add("name 2", "value 2+1");
        parts.add("name 2", "value 2+2");
        parts.add("name 3", null);

        Resource logo = new ClassPathResource("/org/springframework/http/converter/logo.jpg");
        parts.add("logo", logo);

        // SPR-12108
        Resource utf8 = new ClassPathResource("/org/springframework/http/converter/logo.jpg") {
            @Override
            public String getFilename() {
                return "Hall\u00F6le.jpg";
            }
        };
        parts.add("utf8", utf8);

        Source xml = new StreamSource(new StringReader("<root><child/></root>"));
        HttpHeaders entityHeaders = new HttpHeaders();
        entityHeaders.setContentType(MediaType.TEXT_XML);
        HttpEntity<Source> entity = new HttpEntity<>(xml, entityHeaders);
        parts.add("xml", entity);

        MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
        this.converter.write(parts, new MediaType("multipart", "form-data", StandardCharsets.UTF_8), outputMessage);

        final MediaType contentType = outputMessage.getHeaders().getContentType();
        assertNotNull("No boundary found", contentType.getParameter("boundary"));

        // see if Commons FileUpload can read what we wrote
        FileItemFactory fileItemFactory = new DiskFileItemFactory();
        FileUpload fileUpload = new FileUpload(fileItemFactory);
        RequestContext requestContext = new MockHttpOutputMessageRequestContext(outputMessage);
        List<FileItem> items = fileUpload.parseRequest(requestContext);
        assertEquals(6, items.size());
        FileItem item = items.get(0);
        assertTrue(item.isFormField());
        assertEquals("name 1", item.getFieldName());
        assertEquals("value 1", item.getString());

        item = items.get(1);
        assertTrue(item.isFormField());
        assertEquals("name 2", item.getFieldName());
        assertEquals("value 2+1", item.getString());

        item = items.get(2);
        assertTrue(item.isFormField());
        assertEquals("name 2", item.getFieldName());
        assertEquals("value 2+2", item.getString());

        item = items.get(3);
        assertFalse(item.isFormField());
        assertEquals("logo", item.getFieldName());
        assertEquals("logo.jpg", item.getName());
        assertEquals("image/jpeg", item.getContentType());
        assertEquals(logo.getFile().length(), item.getSize());

        item = items.get(4);
        assertFalse(item.isFormField());
        assertEquals("utf8", item.getFieldName());
        assertEquals("Hall\u00F6le.jpg", item.getName());
        assertEquals("image/jpeg", item.getContentType());
        assertEquals(logo.getFile().length(), item.getSize());

        item = items.get(5);
        assertEquals("xml", item.getFieldName());
        assertEquals("text/xml", item.getContentType());
        verify(outputMessage.getBody(), never()).close();
    }

    // SPR-13309

    @Test
    public void writeMultipartOrder() throws Exception {
        MyBean myBean = new MyBean();
        myBean.setString("foo");

        MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
        parts.add("part1", myBean);

        HttpHeaders entityHeaders = new HttpHeaders();
        entityHeaders.setContentType(MediaType.TEXT_XML);
        HttpEntity<MyBean> entity = new HttpEntity<>(myBean, entityHeaders);
        parts.add("part2", entity);

        MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
        this.converter.setMultipartCharset(StandardCharsets.UTF_8);
        this.converter.write(parts, new MediaType("multipart", "form-data", StandardCharsets.UTF_8), outputMessage);

        final MediaType contentType = outputMessage.getHeaders().getContentType();
        assertNotNull("No boundary found", contentType.getParameter("boundary"));

        // see if Commons FileUpload can read what we wrote
        FileItemFactory fileItemFactory = new DiskFileItemFactory();
        FileUpload fileUpload = new FileUpload(fileItemFactory);
        RequestContext requestContext = new MockHttpOutputMessageRequestContext(outputMessage);
        List<FileItem> items = fileUpload.parseRequest(requestContext);
        assertEquals(2, items.size());

        FileItem item = items.get(0);
        assertTrue(item.isFormField());
        assertEquals("part1", item.getFieldName());
        assertEquals("{\"string\":\"foo\"}", item.getString());

        item = items.get(1);
        assertTrue(item.isFormField());
        assertEquals("part2", item.getFieldName());

        // With developer builds we get: <MyBean><string>foo</string></MyBean>
        // But on CI server we get: <MyBean xmlns=""><string>foo</string></MyBean>
        // So... we make a compromise:
        assertThat(item.getString(), allOf(startsWith("<MyBean"), endsWith("><string>foo</string></MyBean>")));
    }

    private static class MockHttpOutputMessageRequestContext implements RequestContext {

        private final MockHttpOutputMessage outputMessage;

        private MockHttpOutputMessageRequestContext(MockHttpOutputMessage outputMessage) {
            this.outputMessage = outputMessage;
        }

        @Override
        public String getCharacterEncoding() {
            MediaType type = this.outputMessage.getHeaders().getContentType();
            return (type != null && type.getCharset() != null ? type.getCharset().name() : null);
        }

        @Override
        public String getContentType() {
            MediaType type = this.outputMessage.getHeaders().getContentType();
            return (type != null ? type.toString() : null);
        }

        @Override
        @Deprecated
        public int getContentLength() {
            return this.outputMessage.getBodyAsBytes().length;
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(this.outputMessage.getBodyAsBytes());
        }
    }

    public static class MyBean {

        private String string;

        public String getString() {
            return this.string;
        }

        public void setString(String string) {
            this.string = string;
        }
    }

}