2015-06-07 24 views
5

Meine Einheit:Null-ID Eigenschaft, wenn deserialize json mit Jackson und Jackson2HalModule of Spring Hateoas

public class User { 

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

    // getters and setters 
} 

Datei test.json (Antwort von REST-Webservice):

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

Und meine Testklasse:

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()); 
    } 
} 

Der zweite Test besteht aber nicht der erste. Ich verstehe nicht, weil die ID-Eigenschaft im Benutzer die einzige fehlt (Mail und aktivierten Eigenschaften sind nicht leer) ...

Was muss ich tun, um es zu beheben? Ist es ein Bug in Jackson oder Spring Jackson2HalModule?

Sie können reproduzieren, indem Sie meine Feder-homoas Gabel repository klonen und Einheitstests starten.

Antwort

9

Eigentlich war es wegen der Resource Klasse, die gebaut wird, um den Inhalt Ihrer Bean zu wickeln. Die Eigenschaft content ist mit @JsonUnwrapped gekennzeichnet, so dass die Klasse Resource Ihre Bean in dieser Eigenschaft zuordnen kann, während sich die Eigenschaften von bohnen im json auf derselben Ebene wie die Eigenschaft _links befinden. Mit dieser Annotation ist es möglich, dass der Name der Eigenschaft mit dem Wrapper und der inneren Bean in Konflikt steht. Dies ist genau der Fall, da die Resource Klasse eine id Eigenschaft hat, die von der ResourceSupport Klasse geerbt wurde, und diese Eigenschaft wird leider mit @JsonIgnore kommentiert.

Es gibt eine Problemumgehung für dieses Problem. Sie können eine neue MixIn Klasse von der ResourceSupportMixin Klasse geerbt erstellen und die getId() Methode mit @JsonIgnore(false) Anmerkung außer Kraft setzen:

public abstract class IdResourceSupportMixin extends ResourceSupportMixin { 

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

Dann müssen Sie nur noch Ihre IdResourceSupportMixin Klasse Ihren ObjectMapper hinzufügen:

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

Es sollte das Problem lösen.

+1

gleiche Problem mit 'feder hateoas' und' feder boot', so hatte ich die 'id' etwas anderes – cahen

+0

Sind zu umbenennen Bist du sicher, dass es funktioniert? – Gazeciarz

+0

Es war vor einem Jahr, aber wenn ich mich richtig erinnere, funktioniert es tatsächlich nicht wegen eines Kompilierungsfehlers, denke ich ... Die einzige Lösung, die ich gefunden habe, ist Cahens. Sie müssen Ihre ID-Eigenschaft in etwas anderes umbenennen. – mfalaize

0

Dieser arbeitete für mich:

public class User extends ResourceSupport { 

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

    // getters and setters 
} 

Auch Ihr http Client ändern PagedResources <User> statt PagedResources<Resource<User>>

0

Mit diesem Code zurückkehren Sie alle @Entity Bohnen eine Änderung der Konfiguration finden Id Wert zu entlarven:

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; 
    } 

}