Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
108 views
in Technique[技术] by (71.8m points)

java - Custom HTTP Message Converter Not Being Used, 415 Unsupproted Media Type

I am creating a test application to achieve conversion from XML String to Employee object before being passed to the controller. I don't want to use JAXB converter because the purpose is to test Custom HTTP Message Converter which I am going to use in my actual use case that involves XML parsing using SAX parser and some complex rules.

Here are the key steps performed:

  • Creation of Employee.java Class : Domain Object
  • Creation of EmployeeManagementController.java class : Spring MVC Controller for Managing Employee
  • Creation of EmployeeConverter.java : Custom Converter for Converting XML String to Employee Object.
  • Creation of employee-servlet.xml : Spring Configuration file
  • Creation of web.xml : The Deployment Descriptor

Employee.java

@Component
@XmlRootElement(name="employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee{

@XmlElement(name="name")
String name;
@XmlElement(name="designation")
String designation;
@XmlElement(name="skill")
String skill;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}

}

EmployeeManagementController.java

@Controller
@RequestMapping(value="/emp")
public class EmployeeManagementController {

    @RequestMapping(value="/add/employee", method=RequestMethod.POST, consumes="text/html")
    public void addEmployee(@RequestBody Employee employee){
        System.out.println("Employee Name : "+employee.getName());
        System.out.println("Employee Designation : "+employee.getDesignation());
        System.out.println("Employee Skill : "+employee.getSkill());

    }


}

EmployeeConverter.java

@Component
public class EmployeeConverter extends AbstractHttpMessageConverter<Employee>{

    @Override
    protected Employee readInternal(Class<? extends Employee> arg, HttpInputMessage inputMsg) throws IOException,
            HttpMessageNotReadableException {
        // TODO Auto-generated method stub
        Map<String,String> paramMap = getPostParameter(inputMsg);
        BufferedReader file =  new BufferedReader(new StringReader(paramMap.get("xml")));
        Employee employee = null;
        JAXBContext jaxbContext;
        try {
            jaxbContext = JAXBContext.newInstance(Employee.class);
            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
            employee = (Employee) jaxbUnmarshaller.unmarshal(file);
        } catch (JAXBException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(employee);
        return employee;
    }

    @Override
    protected boolean supports(Class<?> type) {
        if(type.getSimpleName().equalsIgnoreCase("Employee")){
            return true;
        }
        return false;
    }

    @Override
    protected void writeInternal(Employee arg0, HttpOutputMessage arg1)
            throws IOException, HttpMessageNotWritableException {
        // TODO Auto-generated method stub

    }

    private Map<String,String> getPostParameter(HttpInputMessage input) throws IOException{
        String payload = null;
        String[] params = null;
        BufferedReader buf = new BufferedReader(new InputStreamReader(input.getBody()));
        Map<String,String> paramMap = new HashMap<String,String>();

        String line="";
        while((line = buf.readLine())!=null){
            payload = payload+line;
        }

        if(payload.contains("&")){
            params = payload.split("&");
            for(String param : params){
                paramMap.put(param.split("=")[0],param.split("=")[1]);
            }
        }

        return paramMap;
    }


}

employee-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                xmlns:context="http://www.springframework.org/schema/context"
                xmlns:mvc="http://www.springframework.org/schema/mvc"
                xmlns:util="http://www.springframework.org/schema/util"
                xsi:schemaLocation="http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context-3.1.xsd
                http://www.springframework.org/schema/mvc
                http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
                http://www.springframework.org/schema/util
                http://www.springframework.org/schema/util/spring-util-3.1.xsd">

         <mvc:default-servlet-handler/> 

        <context:component-scan base-package="com"/>

         <mvc:annotation-driven>
            <mvc:message-converters>
                <bean class="com.converter.EmployeeConverter"/>             
            </mvc:message-converters>
        </mvc:annotation-driven>

        <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
            <property name="mediaTypes">
                <map>
                    <entry key="json" value="application/json"/>
                    <entry key="xml" value="text/xml"/>
                    <entry key="htm" value="text/html"/>
                </map>
            </property>
            <property name="defaultContentType" value="text/html"/>
        </bean>

        <!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
            <property name="messageConverters">    
                <util:list id="beanList">
                    <ref bean="employeeConverter"/>       
                </util:list>
            </property>
        </bean>  -->

        <!-- <bean id="employeeConverter" class="com.converter.EmployeeConverter"/> -->



</beans>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>TestConverter</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>    
  </welcome-file-list>

  <servlet>
    <servlet-name>employee</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
  <servlet-name>employee</servlet-name>
  <url-pattern>/*</url-pattern>
  </servlet-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/employee-servlet.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

</web-app>

When I Use FireFox RestClient I get Response as : 415 Unsupproted Media Type.

I set the Content-Type and Accept header as text/xml in RestClient and pass the following XML string in the body as parameter:

xml=<employee><name>Jack</name><designation>Account Director</designation><skill>Commuication</skill></employee>

Can somebody help and let me know what changes are required? I have also tried to use AnnotationMethodHandlerAdapter for registering the message converter.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

1. Set Media Type

Comparing your implementation with some HttpMessageConverter implementations provided by Spring (for example ′MappingJackson2HttpMessageConverter′), shows that you missed to define the supportedMediaTypes.

The common way* of HttpMessageConverter that extends AbstractHttpMessageConverter<T> is to set the media type in the constructor, by using the super constructor AbstractHttpMessageConverter.(MediaType supportedMediaType).

 public class EmployeeConverter extends AbstractHttpMessageConverter<Employee> {
      public EmployeeConverter() {
            super(new MediaType("text", "xml", Charset.forName("UTF-8")));
      }
 }

BTW 1: you can also register more then one media type**

super(MediaType.APPLICATION_XML,
      MediaType.TEXT_XML,
      new MediaType("application", "*+xml")); 

BTW 2: for xml conterter one should think extending from AbstractXmlHttpMessageConverter<T>

2. Register you Converter

<mvc:annotation-driven>
    <mvc:message-converters>
       ...
       <bean class="com.example.YourConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven>

The major drawback of <mvc:message-converters> is, that this replace the default configuration, so you must also register all default HttpMessageConverter explicit.

To keep the default message convertes you need to use: <mvc:message-converters register-defaults="true">...

  • *used by the other implementations like MappingJackson2HttpMessageConverter′
  • **example take from AbstractXmlHttpMessageConverter<T>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...