2

I'm testing a new rest service that I've implemented. This service returns a Json through @ResponseBody. In each controller, I return the same structure:

-code

-message

-list of objects

The object that i return is a message with a list which extends to its parent class getting the code and message. These are my classes:

private class SimpleMessage{
        ResponseCode code;
        String message;
        public ResponseCode getCode() {
            return code;
        }
        public void setCode(ResponseCode code) {
            this.code = code;
        }
        public String getMessage() {
            return message;
        }
        public void setMessage(String message) {
            this.message = message;
        }
        public void setCodeAndMessage(ResponseCode code, String message){
            this.code = code;
            this.message = message;
        }
    }

private class MessageResponse<T> extends SimpleMessage{
    List<T> list;
    public List<T> getList() {
        return list;
    }
    public void setList(List<T> list) {
        this.list = list;
    }
}   

If I try to return the SimpleMessage, it works fine. But the problem is relative to the MessageResponse class. If I return this class with an instance of the class User for example in the list, it runs in an infinite loop until I stop the tomcat server.

This is my controller

public @ResponseBody SimpleMessage isUserSuscribed(@RequestBody String data){
    MessageResponse<User> msg = new MessageResponse<User>();
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
    JsonNode node;
    try {
        node = mapper.readTree(data);
        BasicUser manager = mapper.convertValue(node.get("manager"), BasicUser.class); 
        User user = userService.getUserByOpenid(mapper.convertValue(node.get("openid"), String.class));
        msg.setList(Lists.newArrayList(user));
    } catch (JsonProcessingException e) {
        log.debug(e.toString());
        msg.setCodeAndMessage(ResponseCode.error, "Malformed JSON \n" + e.getMessage());
    } catch (IOException e1) {
        log.debug(e1.toString());
        msg.setCodeAndMessage(ResponseCode.error, "Application error");
    }   
    msg.setCodeAndMessage(ResponseCode.success, "success");
    return msg;
}

The User class:

public class User extends AbstractPropertySearcher{

    private String username;

    private String password;

    private String email;

    private Boolean active;

    private String metadata;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Boolean getActive() {
        return active;
    }

    public void setActive(Boolean active) {
        this.active = active;
    }

    public String getMetadata() {
        return getMeta().getMetadata();
    }

    public void setMetadata(String metadata) {
        this.metadata = metadata;
    }

    public enum KnownUsers{
        TEST, SYSTEM
    }

    public User() {
        this.roles = new HashSet<String>();
        this.profiles = new HashSet<String>();
        this.geoareas = new HashSet<String>();
        this.properties = new HashSet<Property>();
    }

    public User(String username) {
        this.username = username;
        this.roles = new HashSet<String>();
        this.profiles = new HashSet<String>();
        this.geoareas = new HashSet<String>();
        this.properties = new HashSet<Property>();
    }

    public User(User o) {
        try{
            PropertyUtils.copyProperties(this, o);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Set<String> roles;

    private Set<String> profiles;

    private Set<String> geoareas;

    public Set<String> getRoles() {
        return roles;
    }
    public void setRoles(Set<String> roles) {
        this.roles = roles;
    }
    public Set<String> getProfiles() {
        return profiles;
    }
    public void setProfiles(Set<String> profiles) {
        this.profiles = profiles;
    }
    public Set<String> getGeoareas() {
        return geoareas;
    }
    public void setGeoareas(Set<String> geoareas) {
        this.geoareas = geoareas;
    }

    private Set<Property> properties;
    private Map<String,Property> mappedProperties;

    public Map<String,Property> getMappedProperties(){
        if(mappedProperties==null){
            mappedProperties = new HashMap<String,Property>();
            for(Property prop : getProperties()){
                mappedProperties.put(prop.getProperty(),prop);
            }           
        }
        return mappedProperties;
    }

    public Property getPropertyByName(KnownProperty knownProperty) throws PropertyNotFoundException{
        return getPropertyByName(knownProperty.getPropertyName());
    }

    public void setProperty(Property property){
        setProperty(properties, property);
    }

    public boolean hasRole(Role.KnownRoles role){
        return roles.contains(role.name());
    }

    public Set<Property> getProperties() {
        return properties;
    }
    public void setProperties(Set<Property> properties) {
        this.properties = properties;
    }

    public String toString(){
        return getUsername();
    }

    public int hashCode(){
        return toString().hashCode();
    }

    public boolean equals(Object o){
        if(o instanceof User){
            return getUsername().equals(((User) o).getUsername());
        }
        return false;
    }

    public Property getBannerProperty() throws PropertyNotFoundException{
        return AbstractPropertySearcher.getPropertyByName(getProperties(), KnownProperty.BANNER.getPropertyName());
    }

    private Metadata meta;

    public Metadata getMeta(){
        if(meta == null){
            meta = new Metadata(metadata);
        }
        return meta;
    }

    public enum KnownMetaProperty{
        REGISTRATION_DATE, LAST_ACCESS_DATE
    }

    public String getRegistrationDate(){
        return getMeta().getVariable(KnownMetaProperty.REGISTRATION_DATE.name());
    }

    public String getLastAccessDate(){
        return getMeta().getVariable(KnownMetaProperty.LAST_ACCESS_DATE.name());
    }

}

This is the error in the log:

org.apache.jasper.JasperException: javax.servlet.ServletException: java.lang.StackOverflowError

Could anybody help me with this issue? Thank you

mannuk
  • 1,259
  • 5
  • 21
  • 43
  • Have a look at this URL. This is very similar to your issue.http://stackoverflow.com/questions/13630096/cyclic-references-in-a-bidirectional-many-to-many-relationship – Dark Knight Nov 12 '13 at 09:53
  • Yes, I've taken a look at those issues but I don't have Bidireccional dependences in my case. – mannuk Nov 12 '13 at 09:55
  • Show us User class please – mvb13 Nov 12 '13 at 10:19
  • Hi @mvb13 ;) The class has a lot of things. It is a multi maven project (Parent, childs... lot of complex) Should I map to a simplier User class? – mannuk Nov 12 '13 at 10:27
  • It looks fine. I can suggest to create some test class to put there some part of information to check if it works on simplify user and after that to add class properties one by one. – mvb13 Nov 12 '13 at 10:44
  • I will check it tomorrow @mvb13. I will keep you informed – mannuk Nov 12 '13 at 18:32

0 Answers0