2015-06-07 10 views
5

mia entità:proprietà id Null quando JSON deserialize con Jackson e Jackson2HalModule della primavera hateoas

public class User { 

    private Integer id; 
    private String mail; 
    private boolean enabled; 

    // getters and setters 
} 

File test.json (risposta da REST webservice):

{ 
"_embedded" : { 
    "users" : [ { 
    "id" : 1, 
    "mail" : "[email protected]", 
    "enabled" : true, 
    "_links" : { 
     "self" : { 
     "href" : "http://localhost:8080/api/users/1" 
     } 
    } 
    } ] 
} 
} 

E la mia classe di test:

public class TestJson { 

    private InputStream is; 
    private ObjectMapper mapper; 

    @Before 
    public void before() { 
     mapper = new ObjectMapper(); 
     mapper.registerModule(new Jackson2HalModule()); 
     mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 

     is = TestJson.class.getResourceAsStream("/test.json"); 
    } 

    @After 
    public void after() throws IOException { 
     is.close(); 
    } 

    @Test 
    public void test() throws IOException { 
     PagedResources<Resource<User>> paged = mapper.readValue(is, new TypeReference<PagedResources<Resource<User>>>() {}); 
     Assert.assertNotNull(paged.getContent().iterator().next().getContent().getId()); 
    } 

    @Test 
    public void testResource() throws IOException { 
     PagedResources<User> paged = mapper.readValue(is, new TypeReference<PagedResources<User>>() {}); 
     Assert.assertNotNull(paged.getContent().iterator().next().getId()); 
    } 
} 

Il secondo test passa ma non il primo. Non capisco perché la proprietà id dell'utente è l'unica mancante (le proprietà mail e abilitate non sono vuote) ...

Cosa devo fare per risolverlo? È un bug in Jackson o Spring Jackson2HalModule?

È possibile riprodurre clonando la forcelladella mia molla di lancio e test di unità di lancio.

risposta

9

In realtà, era dovuto alla classe Resource che è stata creata per avvolgere il contenuto del bean. La proprietà content è annotata da @JsonUnwrapped in modo che la classe Resource possa mappare il bean in questa proprietà, mentre in json le proprietà bean si trovano allo stesso livello della proprietà _links. Con questa annotazione, è possibile che il nome della proprietà sia in conflitto con il wrapper e il bean interno. È esattamente il caso in cui la classe Resource ha una proprietà id ereditata dalla classe ResourceSupport e questa proprietà è annotata tristemente da @JsonIgnore.

Esiste una soluzione alternativa per questo problema. È possibile creare una nuova MixIn classe ereditata dalla classe ResourceSupportMixin e sovrascrivere il metodo getId() con @JsonIgnore(false) annotazione:

public abstract class IdResourceSupportMixin extends ResourceSupportMixin { 

    @Override 
    @JsonIgnore(false) 
    public abstract Link getId(); 
} 

Poi basta aggiungere la classe IdResourceSupportMixin al ObjectMapper:

mapper.addMixInAnnotations(ResourceSupport.class, IdResourceSupportMixin.class); 

Dovrebbe risolvere il problema.

+1

stesso problema con 'molla hateoas' e' primavera-boot', così ho dovuto rinominare il 'id' a qualcos'altro – cahen

+0

Are Sei sicuro che funzioni? – Gazeciarz

+0

Era un anno fa, ma se ricordo bene, in realtà non funziona a causa di un errore di compilazione, penso ... L'unica soluzione che ho trovato è quella di Cahen. Devi rinominare la tua proprietà id in qualcos'altro. – mfalaize

0

questo ha funzionato per me:

public class User extends ResourceSupport { 

    @JsonIgnore(false) 
    private Integer id; 
    private String mail; 
    private boolean enabled; 

    // getters and setters 
} 

Inoltre, modificare il client http per tornare PagedResources <User> invece di PagedResources<Resource<User>>

0

Con questo codice è possibile trovare tutti i fagioli @Entity un cambiamento della configurazione per esporre il valore Id:

import java.util.LinkedList; 
import java.util.List; 

import javax.persistence.Entity; 

import org.springframework.beans.factory.config.BeanDefinition; 
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; 
import org.springframework.core.type.filter.AnnotationTypeFilter; 
import org.springframework.data.rest.core.config.RepositoryRestConfiguration; 
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter; 
import org.springframework.stereotype.Component; 

import com.rvillalba.exampleApiHateoas.entity.Example; 

import lombok.extern.slf4j.Slf4j; 

@Component 
@Slf4j 
public class SpringDataRestCustomization extends RepositoryRestConfigurerAdapter { 

    @Override 
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { 
     listMatchingClasses(Entity.class).forEach(entity -> config.exposeIdsFor(entity)); 
    } 

    public List<Class> listMatchingClasses(Class annotationClass) { 
     List<Class> classes = new LinkedList<Class>(); 
     ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(true); 
     scanner.addIncludeFilter(new AnnotationTypeFilter(annotationClass)); 
     for (BeanDefinition bd : scanner.findCandidateComponents(Example.class.getPackage().getName())) { 
      try { 
       classes.add(Class.forName(bd.getBeanClassName())); 
      } catch (ClassNotFoundException e) { 
       log.error("listMatchingClasses problem", e); 
      } 
     } 
     return classes; 
    } 

} 
Problemi correlati