Announcement Announcement Module
Collapse
No announcement yet.
RestTemplate, not marked as ignorable Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • RestTemplate, not marked as ignorable

    I have got the following situation :

    a webapp serving Spring Rest websevice :
    http://localhost:8080/webapp-domain/hotels/1.json

    a client webapp, I'm using a RestTemplate (defaults maintained)

    the two webapps are running within two jvms

    both client webapp and (REST) server webapp shares model-project (contains the JPA pojos)

    I'm doing a unit test from my client webapp to invoke my REST service, here are snippets from configurations and code files :


    applicationContext.xml
    Code:
    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <property name="messageConverters">
    <list>
    <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
    </list>
    </property>
    </bean>
    The Pojo :
    Code:
    package fr.company.model;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.JoinTable;
    import javax.persistence.ManyToMany;
    import javax.persistence.OneToMany;
    import javax.persistence.SequenceGenerator;
    import javax.persistence.Table;
    import javax.persistence.UniqueConstraint;
    
    import org.apache.commons.lang.builder.ToStringBuilder;
    import org.apache.commons.lang.builder.ToStringStyle;
    
    /**
     * Hotel model class
     * 
     */
    @Entity
    @Table(name = "hotel", uniqueConstraints = @UniqueConstraint(columnNames = "code"))
    public class Hotel extends AbstractPersistable<Integer> {
    	private static final long serialVersionUID = -6186187114090017681L;
    
    	private Integer id;
    	private String code;
    	private String label;
    	private String description;
    	private List<Location> locations = new ArrayList<Location>(0);
    	private List<Room> rooms = new ArrayList<Room>(0);
    	private List<Booking> bookings = new ArrayList<Booking>(0);
    	private List<User> users = new ArrayList<User>(0);
    
    	/**
    	 * Default constructor
    	 */
    	public Hotel() {
    	}
    
    	/**
    	 * @{inheritDoc
    	 */
    	@Id
    	@Column(name = "id", unique = true, nullable = false)
    	@GeneratedValue(generator = "hotelIdGenerator")
    	@SequenceGenerator(name = "hotelIdGenerator", sequenceName = "hotel_id_seq")
    	public Integer getId() {
    		return this.id;
    	}
    
    	/**
    	 * @param id
    	 */
    	public void setId(Integer id) {
    		this.id = id;
    	}
    
    	/**
    	 * @return
    	 */
    	@Column(name = "code", unique = true, nullable = false)
    	public String getCode() {
    		return this.code;
    	}
    
    	/**
    	 * @param code
    	 */
    	public void setCode(String code) {
    		this.code = code;
    	}
    
    	/**
    	 * @return
    	 */
    	@Column(name = "label")
    	public String getLabel() {
    		return this.label;
    	}
    
    	/**
    	 * @param label
    	 */
    	public void setLabel(String label) {
    		this.label = label;
    	}
    
    	/**
    	 * @return
    	 */
    	@Column(name = "description")
    	public String getDescription() {
    		return this.description;
    	}
    
    	/**
    	 * @param description
    	 */
    	public void setDescription(String description) {
    		this.description = description;
    	}
    
    	/**
    	 * @return
    	 */
    	@OneToMany(fetch = FetchType.LAZY, mappedBy = "hotel")
    	public List<Location> getLocations() {
    		return this.locations;
    	}
    
    	/**
    	 * @param locations
    	 */
    	public void setLocations(List<Location> locations) {
    		this.locations = locations;
    	}
    
    	/**
    	 * @return
    	 */
    	@OneToMany(fetch = FetchType.LAZY, mappedBy = "hotel")
    	public List<Room> getRooms() {
    		return this.rooms;
    	}
    
    	/**
    	 * @param rooms
    	 */
    	public void setRooms(List<Room> rooms) {
    		this.rooms = rooms;
    	}
    
    	/**
    	 * @return
    	 */
    	@OneToMany(fetch = FetchType.LAZY, mappedBy = "hotel")
    	public List<Booking> getBookings() {
    		return this.bookings;
    	}
    
    	/**
    	 * @param bookings
    	 */
    	public void setBookings(List<Booking> bookings) {
    		this.bookings = bookings;
    	}
    
    	/**
    	 * @return the users
    	 */
    	@ManyToMany(fetch = FetchType.LAZY)
    	@JoinTable(name = "user_hotel", 
    			joinColumns = { @JoinColumn(name = "hotel_id", nullable = false, updatable = false) }, 
    			inverseJoinColumns = { @JoinColumn(name = "user_id", nullable = false, updatable = false) })
    	public List<User> getUsers() {
    		return users;
    	}
    
    	/**
    	 * @param users the users to set
    	 */
    	public void setUsers(List<User> users) {
    		this.users = users;
    	}
    
    	/**
    	 * {@inheritDoc}
    	 */
    	@Override
    	public String toString() {
    		return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
    				.appendSuper(super.toString()).append("code", code).append(
    						"label", label).toString();
    	}
    }
    The Service :
    Code:
        @Override
        public HotelDto loadHotel(Integer id) {
    	Hotel hotel = restTemplate.getForObject(restServerHost + "/hotels/{id}.json", Hotel.class,
    		id);
    	return new HotelDto(hotel.getId());
        }

    Exception :
    Code:
    org.springframework.web.client.ResourceAccessException: I/O error: Unrecognized field "hotel" (Class fr.company.model.Hotel), not marked as ignorable
     at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@1049d3; line: 1, column: 2]; nested exception is org.codehaus.jackson.map.JsonMappingException: Unrecognized field "hotel" (Class fr.company.model.Hotel), not marked as ignorable
     at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@1049d3; line: 1, column: 2]
    	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:359)
    	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:307)
    	at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:177)
    	at fr.company.web.server.BookingServiceImpl.loadHotel(BookingServiceImpl.java:35)
    	at fr.company.web.server.BookingServiceGwtTest.testlLoadHotel(BookingServiceGwtTest.java:23)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
    	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    Caused by: org.codehaus.jackson.map.JsonMappingException: Unrecognized field "hotel" (Class fr.company.model.Hotel), not marked as ignorable
     at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@1049d3; line: 1, column: 2]
    	at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:159)
    	at org.codehaus.jackson.map.deser.StdDeserializationContext.unknownFieldException(StdDeserializationContext.java:174)
    	at org.codehaus.jackson.map.deser.StdDeserializer.reportUnknownProperty(StdDeserializer.java:317)
    	at org.codehaus.jackson.map.deser.StdDeserializer.handleUnknownProperty(StdDeserializer.java:303)
    	at org.codehaus.jackson.map.deser.BeanDeserializer.handleUnknownProperty(BeanDeserializer.java:505)
    	at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:357)
    	at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:281)
    	at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:1282)
    	at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:927)
    	at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:109)
    	at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:143)
    	at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:60)
    	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:352)
    	... 32 more

  • #2
    It's finally a MappingJackson issue

    After investigating the problem deeply, it appears that the problem is a Jackson parser nor than a spring one.

    Comment


    • #3
      Have you resolved the problem?
      I have the same problem

      Comment


      • #4
        how did u fix it?

        yeah, if you fixed it, please post few lines describing your solution...

        Comment


        • #5
          To resolve this we need to set Fail_on_unknown_properties to false in jackson object mapper.

          It can be done either by including this class in path
          Code:
          @Component
          public class JsonObjectMapperConfiguration implements BeanPostProcessor {
          
              private static final Logger logger = Logger.getLogger(JsonObjectMapperConfiguration.class);
          
              public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
                  return bean;
              }
          
              public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                  if (bean instanceof AnnotationMethodHandlerAdapter) {
                      AnnotationMethodHandlerAdapter adapter = (AnnotationMethodHandlerAdapter) bean;
                      HttpMessageConverter<?>[] converters = adapter.getMessageConverters();
                      for (HttpMessageConverter<?> converter : converters) {
                          if (converter instanceof MappingJacksonHttpMessageConverter) {
                              MappingJacksonHttpMessageConverter jsonConverter = (MappingJacksonHttpMessageConverter) converter;
                              ObjectMapper newObjectMapper = new ObjectMapper();
                              newObjectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                              jsonConverter.setObjectMapper(newObjectMapper);
                          }
                      }
                  }
                  return bean;
              }
          
          
          }
          or by creating a new ObjectMapper as below and setting in {springconfig}.xml

          Code:
          ObjectMapper newObjectMapper = new ObjectMapper();
                              newObjectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
          
          bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">

          Comment


          • #6
            If you fail on unknown properties, all the attributes and children of that property will not get parsed. In the hotel example, that's the top level element, so there'd be nothing to get.

            Use this:

            Code:
            public class ExtendedMappingJacksonJsonView extends MappingJacksonJsonView {
            
            	@SuppressWarnings("unchecked")
            	@Override
            	protected Object filterModel(Map<String, Object> model)
            	{
            		Object result = super.filterModel(model);
            		if (!(result instanceof Map))
            		{
            			return result;
            		}
            		
            		Map map = (Map) result;
            		if (map.size() == 1)
            		{
            			return map.values().toArray()[0];
            
            		}
            		return map;
            	}
            }
            It'll create a JSON representation that Jackson knows how to parse.

            Comment

            Working...
            X