2014-11-17 18 views
5

Tôi đang phải vật lộn với điều này:Spring MVC cấu hình + Jackson + Ổi Multimap

Chúng tôi có một lớp Bảng với một Multimap Ổi (mã đơn giản, về cơ bản 1 thành viên, 2 nhà thầu, phương thức getter và setter cho Multimap):

public class Table { 

    private LinkedHashMultimap<String,Field> fields; 

    public Table(){ 
     this.fields = LinkedHashMultimap.create(); 
    }; 

    public Table (LinkedHashMultimap<String, Field> fields){ 
     this.fields= fields; 
    } 

    public LinkedHashMultimap<String, Field> getFields() { 
     return fields; 
    } 

    public void setFields(LinkedHashMultimap<String, Field> fields) { 
     this.fields = fields; 
    } 
} 

Và tôi muốn nối tiếp điều này bằng cách sử dụng Spring MVC 3.2.11 sử dụng jackson 2.4.3.

POM phụ thuộc có liên quan bao gồm:

<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-core</artifactId> 
    <version>2.4.3</version> 
    <scope>compile</scope> 
</dependency> 
<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-databind</artifactId> 
    <version>2.4.3</version> 
    <scope>compile</scope> 
</dependency> 
<dependency> 
    <groupId>com.fasterxml.jackson.datatype</groupId> 
    <artifactId>jackson-datatype-guava</artifactId> 
    <version>2.4.3</version> 
    <scope>compile</scope> 
</dependency> 
<dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-context</artifactId> 
    <version>3.2.11.RELEASE</version> 
    <scope>compile</scope> 
</dependency> 
<dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-webmvc</artifactId> 
    <version>3.2.11.RELEASE</version> 
    <scope>compile</scope> 
</dependency> 
<dependency> 
    <groupId>javax.servlet</groupId> 
    <artifactId>servlet-api</artifactId> 
    <version>2.5</version> 
    <scope>provided</scope> 
</dependency> 

My spring.xml VỚI DOANH NGHIỆP trông như thế này (sau đây này example)

<bean id="abstractJacksonObjectMapper" 
     class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" 
     p:targetMethod="registerModule"> 
    <property name="targetObject"> 
     <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" 
       p:indentOutput="true"> 
      <!--<property name="featuresToDisable">--> 
       <!--<util:constant static-field="com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES" />--> 
      <!--</property>--> 
     </bean> 
    </property> 
    <property name="arguments"> 
     <list> 
      <bean class="com.fasterxml.jackson.datatype.guava.GuavaModule" /> 
     </list> 
    </property> 
</bean> 

<bean id="abstractMappingJacksonHttpMessageConverter" 
     class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" 
     abstract="true"/> 

<bean id="abstractMappingJacksonJsonView" 
     class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" 
     abstract="true" 
     p:extractValueFromSingleKeyModel="true"/> 

<bean id="jacksonObjectMapper" parent="abstractJacksonObjectMapper" /> 

<bean id="mappingJacksonHttpMessageConverter" 
     parent="abstractMappingJacksonHttpMessageConverter" 
     p:objectMapper-ref="jacksonObjectMapper" 
     p:supportedMediaTypes="application/json" /> 

<bean id="mappingJacksonJsonView" 
     parent="abstractMappingJacksonJsonView" 
     p:objectMapper-ref="jacksonObjectMapper" 
     p:contentType="application/json" /> 

Tôi cũng thử phương pháp này khác sử dụng một mở rộng Jackson2ObjectMapperFactoryBean:

<!-- Json rendering configuration--> 
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> 
    <property name="order" value="1" /> 
    <property name="mediaTypes"> 
     <map> 
      <entry key="json" value="application/json" /> 
      <entry key="xml" value="application/xml" /> 
     </map> 
    </property> 
    <property name="defaultViews"> 
     <list> 
      <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"> 
       <property name="objectMapper"> 
        <bean class="my.package.Jackson2ObjectMapperFactoryBean"/> 
       </property> 
      </bean> 
     </list> 
    </property> 
    <property name="ignoreAcceptHeader" value="true" /> 
</bean> 

Và sau đó FactoryBean trông như thế này:

package my.package; 

import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.datatype.guava.GuavaModule; 

public class Jackson2ObjectMapperFactoryBean extends org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean{ 

public ObjectMapper getObject(){ 

    ObjectMapper objectMapper =super.getObject(); 
    objectMapper.registerModule(new GuavaModule()); 

    return objectMapper; 
} 

}

Tôi có một class Test rằng hoạt động tốt và không được sử dụng Spring ở tất cả (chỉ là thử nghiệm Table.class + Jackson + ổi) Đơn giản:

Table study = getTable(); 

ObjectMapper mapper = new ObjectMapper(); 
mapper.registerModule(new GuavaModule()); 

String tableString = mapper.writeValueAsString(table); 

Nó nối tiếp đúng:

{ 
    "fields":{ 
    "Field1":[ 
     { 
     "index":0, 
     "header":"Field1", 
     "fieldType":"fieldtype", 
     "description":null, 
     "cleanHeader":null 
     } 
    ], 
    "Field2":[ 
     { 
     "index":1, 
     "header":"Field2", 
     "fieldType":"fieldtype", 
     "description":null, 
     "cleanHeader":null 
     } 
    ] 
    } 
} 

Sử dụng lò xo (bất kỳ của 2 lối vào) tôi nhận được:

{ 
    "fields":{ 
    "empty": false 
    } 
} 

điều khiển của tôi có một chú thích @ResponseBody và nó trả về một Table.

CHỈNH SỬA: Tôi đang gỡ lỗi sâu vào các lớp học mùa xuân (firs time, ;-)) và org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor đang xử lý yêu cầu. Điều này liên quan đến vấn đề của tôi ... Xml mùa xuân của tôi, bằng cách nào đó mâu thuẫn với chú thích @ResponseBody?

Bất kỳ ý tưởng nào tôi đang làm sai?

LƯU Ý: Tôi cần Multimap, không thể là bộ sưu tập Java tiêu chuẩn.

Trả lời

0

Sau khi tất cả tôi phát hiện ra rằng chú thích @ResponseBody đã buộc phải sử dụng một khác nhau "viewResolver", đã được sử dụng Jackson, nhưng không có mô-đun ổi.

Vì vậy, để khắc phục điều này tôi loại bỏ các chú thích @ResponseBody trong phương pháp điều khiển của tôi:

<!-- language: java --> 
@ResponseBody 
@RequestMapping("table") 
public Table getTable() { 

Thật không may, điều này đã trở về: {Bảng: {...}} và được một artefact giới thiệu bởi các ValueHandlder (ModelAttributeMethodProcessor).

Cuối cùng, những gì đang làm việc bây giờ là:

1. Khôi phục @ResponseBody 2. Đăng ký Module ổi trong MappingJackson2HttpMessageConverter mà đi theo mặc định với handler @ResponseBody.

Đây là cách xml mùa xuân trông giống như: Giống sạch và đơn giản hơn:

<!-- JSON parser configuration--> 
<bean id="guavaObjectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"/> 

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> 
    <property name="targetObject"><ref local="guavaObjectMapper" /></property> 
    <property name="targetMethod"><value>registerModule</value></property> 
    <property name="arguments"> 
     <list> 
      <bean id="guavaModule" class="com.fasterxml.jackson.datatype.guava.GuavaModule"/> 
     </list> 
    </property> 
</bean> 


<mvc:annotation-driven> 
    <mvc:message-converters register-defaults="true"> 
     <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
      <property name="objectMapper"> 
       <ref local="guavaObjectMapper"/> 
      </property> 
     </bean> 
    </mvc:message-converters> 
</mvc:annotation-driven> 
1

Tôi nghĩ rằng bạn cần phải thêm phần mvc: messsage-converters vào tệp spring.xml của mình. Ví dụ

<mvc:annotation-driven ignoreDefaultModelOnRedirect="true" > 
    <mvc:message-converters> 
     <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/> 
     <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/> 
     <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/> 
    </mvc:message-converters> 
</mvc:annotation-driven> 
+0

Cảm ơn Katerina! Tôi đã thêm mã của bạn và đã thử với cả hai cách tiếp cận trên .... Tôi nhận được cùng một "trường": {"rỗng": false} kết quả. – Pablo

3

Dunno nếu các giải pháp dưới đây phù hợp với vấn đề của bạn một cách chính xác, nhưng chỉ trong trường hợp bạn muốn cấu hình SpringBootApplication của bạn cũng để serialize ổi, bạn có thể nâng cao lớp học @Configuration của mình bằng cách sử dụng số @Bean như sau:

@Configuration 
public class Application extends SpringBootServletInitializer { 

    @Bean 
    ObjectMapper customizeJacksonConfiguration() { 
     ObjectMapper om = new ObjectMapper(); 
     om.registerModule(new GuavaModule()); 
     return om; 
    } 
} 
+0

Cảm ơn! không sử dụng SpringBootApplication, nhưng có thể hữu ích cho những người sử dụng nó. – Pablo

+0

Nếu bạn có nhiều mô-đun Jackson được nhập vào tệp pom của bạn, điều này sẽ tải tất cả chúng: 'ObjectMapper mapper = new ObjectMapper(); mapper.findAndRegisterModules(); ' – Mark

Các vấn đề liên quan