What is the problem with this java class that consumes a Rest service?

Asked

Viewed 244 times

0

I have a Servlet :

import br.edu.ifpb.pos.model.Art;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;

public class ArtistaServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
//    https://api.vagalume.com.br/rank.php&type=art&radio=coca-cola-fm&apikey=660a4395f992ff67786584e238f501aa  
        String uri = "https://api.vagalume.com.br";
        Client client = ClientBuilder.newClient();
        WebTarget root = client.target(uri).path("rank.php");

        WebTarget comments = root.queryParam("type", "art")
                .queryParam("radio", "coca-cola-fm")
                .queryParam("apikey", "660a4395f992ff67786584e238f501aa");
        Response resp = comments.request().get();
        String json = resp.readEntity(String.class);
        ObjectMapper mapper = new ObjectMapper()
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        List<Art> lista = mapper.readValue(json, new TypeReference<List<Art>>(){
        });
        lista.forEach(c -> System.out.println(c.name()));




            System.out.println(json);
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            out.println("<!DOCTYPE html>");
            out.println("<html>");
            out.println("<head>");
            out.println("<title>API</title>");
            out.println("</head>");
            out.println("<body>");
            for (Art art : lista) {
            out.println("<h3> " + art.name() + "   rank = "  +  art.rank() + "</h3>");            
            }
            out.println("</body>");
            out.println("</html>");
        }
    }
}

and that interface :

package br.edu.ifpb.pos.model;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.immutables.value.Value;

@Value.Immutable
@JsonDeserialize(as = ImmutableArt.class)
@JsonSerialize(as = ImmutableArt.class)
public interface Art {

    public String id();
    public String name();
    public String url();
    public String pic_small();
    public String pic_medium();
    public String uniques();
    public String views();
    public String rank();

}

I’ve used the same logic to consume some services api of the firefly failed to capture the list of artists...
Here is the project that has these classes in github

here’s the mistake:

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
 at [Source: {"art":{"month":{"period":{"year":"2017","month":"12"},"all":[{"id":"3ade68b7g30dd1ea3","name":"Ed Sheeran","url":"https:\/\/www.vagalume.com.br\/ed-sheeran\/","pic_small":"https:\/\/s2.vagalume.com\/ed-sheeran\/images\/profile.jpg","pic_medium":"https:\/\/s2.vagalume.com\/ed-sheeran\/images\/ed-sheeran.jpg","uniques":"208002","views":"366369","rank":"202.6"},{"id":"3ade68b7gb9e80ea3","name":"Demi Lovato","url":"https:\/\/www.vagalume.com.br\/demi-lovato\/","pic_small":"https:\/\/s2.vagalume.com\/demi-lovato\/images\/profile.jpg","pic_medium":"https:\/\/s2.vagalume.com\/demi-lovato\/images\/demi-lovato.jpg","uniques":"189935","views":"281442","rank":"185.0"},{"id":"3ade68b7g3ea23ea3","name":"Kell Smith","url":"https:\/\/www.vagalume.com.br\/kell-smith\/","pic_small":"https:\/\/s2.vagalume.com\/kell-smith\/images\/profile.jpg","pic_medium":"https:\/\/s2.vagalume.com\/kell-smith\/images\/kell-smith.jpg","uniques":"106449","views":"141385","rank":"103.7"},{"id":"3ade68b7g27d72ea3","name":"Thiago Matheus","url":"https:\/\/www.vagalume.com.br\/thiago-matheus\/","pic_small":"https:\/\/s2.vagalume.com\/thiago-matheus\/images\/profile.jpg","pic_medium":"https:\/\/s2.vagalume.com\/thiago-matheus\/images\/thiago-matheus.jpg","uniques":"95219","views":"108237","rank":"92.8"},{"id":"3ade68b6g6b94fda3","name":"Can\u00e7\u00f5es de Natal","url":"https:\/\/www.vagalume.com.br\/cancoes-de-natal\/","pic_small":"https:\/\/s2.vagalume.com\/cancoes-de-natal\/images\/profile.jpg","pic_medium":"https:\/\/s2.vagalume.com\/cancoes-de-natal\/images\/cancoes-de-natal.jpg","uniques":"93987","views":"244174","rank":"91.6"},{"id":"3ade68b5g1b38eda3","name":"Bruno e Marrone","url":"https:\/\/www.vagalume.com.br\/bruno-e-marrone\/","pic_small":"https:\/\/s2.vagalume.com\/bruno-e-marrone\/images\/profile.jpg","pic_medium":"https:\/\/s2.vagalume.com\/bruno-e-marrone\/images\/bruno-e-marrone.jpg","uniques":"87188","views":"146422","rank":"84.9"},{"id":"3ade68b7gc8cb1ea3","name":"Anitta","url":"https:\/\/www.vagalume.com.br\/anitta\/","pic_small":"https:\/\/s2.vagalume.com\/anitta\/images\/profile.jpg","pic_medium":"https:\/\/s2.vagalume.com\/anitta\/images\/anitta.jpg","uniques":"85509","views":"134193","rank":"83.3"},{"id":"3ade68b7gc2b03ea3","name":"1Kilo","url":"https:\/\/www.vagalume.com.br\/1kilo\/","pic_small":"https:\/\/s2.vagalume.com\/1kilo\/images\/profile.jpg","pic_medium":"https:\/\/s2.vagalume.com\/1kilo\/images\/1kilo.jpg","uniques":"84077","views":"140543","rank":"81.9"},{"id":"3ade68b7g73521ea3","name":"Henrique e Juliano","url":"https:\/\/www.vagalume.com.br\/henrique-e-juliano\/","pic_small":"https:\/\/s2.vagalume.com\/henrique-e-juliano\/images\/profile.jpg","pic_medium":"https:\/\/s2.vagalume.com\/henrique-e-juliano\/images\/henrique-e-juliano.jpg","uniques":"75953","views":"162824","rank":"74.0"},{"id":"3ade68b6g39a2fda3","name":"Jorge e Mateus","url":"https:\/\/www.vagalume.com.br\/jorge-e-mateus\/","pic_small":"https:\/\/s2.vagalume.com\/jorge-e-mateus\/images\/profile.jpg","pic_medium":"https:\/\/s2.vagalume.com\/jorge-e-mateus\/images\/jorge-e-mateus.jpg","uniques":"75295","views":"175375","rank":"73.3"}]}}}; line: 1, column: 1]
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)

Firefly API json file:

{
  "art": {
    "week": {
      "period": {
        "year": "2011",
        "week": "34"
      },
      "all": [{
        "id": "3ade68b7g98d71ea3",
        "name": "Bruno Mars",
        "url": "https://www.vagalume.com.br/bruno-mars/",
        "pic_small": "https://www.vagalume.com.br/bruno-mars/images/profile.jpg",
        "pic_medium": "https://www.vagalume.com.br/bruno-mars/images/bruno-mars.jpg",
        "uniques": "84709",
        "views": "183162"
      }]
    }
  }
}

I suspected that my initial structure was not in accordance with the json of the API. So I started mapping the json file to java classes in my tests, minus the Month. It does not appear explicitly in json.
How to deduce it?

1 answer

1


The schema of the JSON you are trying to deserialize does not correspond to the interface structure you have assembled. Its interface Art corresponds to an element of the array called all, that is not the root element of the JSON document. all is a property of month, which is a property of art.

You have to create the remaining interfaces:

Rank

@Value.Immutable
@JsonDeserialize(as = ImmutableRank.class)
@JsonSerialize(as = ImmutableRank.class)
public interface Rank {
    public Art art();
}

Art

Muder Art for:

@Value.Immutable
@JsonDeserialize(as = ImmutableArt.class)
@JsonSerialize(as = ImmutableArt.class)
public interface Art {
    public Month month();
}

Month

@Value.Immutable
@JsonDeserialize(as = ImmutableMonth.class)
@JsonSerialize(as = ImmutableMonth.class)
public interface Month {
    public Period period();

    public List<All> all();
}

Period

@Value.Immutable
@JsonDeserialize(as = ImmutablePeriod.class)
@JsonSerialize(as = ImmutablePeriod.class)
public interface Period {
    public String month();
    public String year();
}

All

@Value.Immutable
@JsonDeserialize(as = ImmutableAll.class)
@JsonSerialize(as = ImmutableAll.class)
public interface All {
    public String id();
    public String name();
    public String url();
    public String pic_small();
    public String pic_medium();
    public String uniques();
    public String views();
    public String rank();
}

Making the requisition

Rank rank = mapper.readValue(json, Rank.class);
rank.art().month().all().forEach(a -> System.out.println(a.name()));
  • thank you very much, thank you very much, you helped a lot... I tried to do the same yesterday, not with interfaces , but with classes, java.Although I didn’t have the Month class, how did Voce deduce it? After all, java even complained that it did not find such a class.. A hug

  • 1

    @Painted by the estate month in JSON ;). When you have some difficulty trying to understand the JSON structure, use a json beautifier, or convert it to Java classes with some tool like jsonschema2pojo.

  • Great tips, these tools. I knew only a few to similar json beautifier. However, I’m still thinking about how the Month class was created.... Thanks guy!!!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.