0

I am making a linechart using MPAndroidCharts that uses an API to receive and display data. (This is the guide I am following: https://learntodroid.com/how-to-display-a-line-chart-in-your-android-app/). I have done everything that the tutorial shows but I seem to keep getting the same error. This is my method where I call the API and attempt to retrieve data from it. The error appears on the x value in the response body.

private void AddCurrentDataValues() {

       saunaDataAPI.getHistoricalData(
               "Sauna1"
       ).enqueue(new Callback<List<SaunaBitResponse.SaunaBit>>() {
           @Override
           public void onResponse(@NonNull Call<List<SaunaBitResponse.SaunaBit>> call, @NonNull Response<List<SaunaBitResponse.SaunaBit>> response) {
               ArrayList<Entry> co2Data = new ArrayList<>();

               if (response.body() != null) {

                   for (int i = 0; i < response.body().size(); i++) {
                       float x = response.body().get(i).time;
                       float y = response.body().get(i).co2;

                       if (y != 0) {
                           co2Data.add(new Entry(x, y));
                       }
                   }
                   Comparator<Entry> comparator = new Comparator<Entry>() {
                       @Override
                       public int compare(Entry o1, Entry o2) {
                           return Float.compare(o1.getX(), o2.getX());
                       }
                   };
                   co2Data.sort(comparator);

                   setLineChartData(co2Data);
               }
           }
           @Override
           public void onFailure(@NonNull Call<List<SaunaBitResponse.SaunaBit>> call, @NonNull Throwable t) {

               t.printStackTrace();
           }
       });
   }

This is my interface to retrieve data from the API:

public interface SaunaDataAPI {
    @Headers({"Accept: application/json"})

    @GET("getMeasurementBySaunaName/{name}")
    Call<List<SaunaBitResponse.SaunaBit>> getHistoricalData (
            @Path("name") String sauna_name
    );

    @GET("getMeasurementById/{id}")
    Call<SaunaBitResponse.SaunaBit> getDataById(
            @Path("id") long id
    );
}

This is the class that handles the response.

public class SaunaBitResponse {

    public List<SaunaBit> saunaBits;

    public static class SaunaBit {
        public String sauna_name;
        public long time;
        public float temp;
        public float co2;
        public float humidity;
    }
}

This is the measurement entity in the API:

@Entity
@Table(name = "Measurement")
public class Measurements {

    @Id
    @Column(name = "measurementId")
    private int id;
    private String saunaName;
    private int Co2;
    private int humidity;
    private int temperature;
    private Time time;
    @ManyToOne(cascade =CascadeType.ALL)
    private SaunaRoom saunaRoom;


    public Measurements() {
    }

    public Measurements(int id, String saunaName, int co2, int humidity, int temperature, Time time,SaunaRoom saunaRoom) {
        this.id = id;
        this.saunaName = saunaName;
        Co2 = co2;
        this.humidity = humidity;
        this.temperature = temperature;
        this.time = time;
        this.saunaRoom= saunaRoom;
    }
    public SaunaRoom getSaunaRoom() {
        return saunaRoom;
    }

    public void setSaunaRoom(SaunaRoom saunaRoom) {
        this.saunaRoom = saunaRoom;
    }



    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getSaunaName() {
        return saunaName;
    }

    public void setSaunaName(String saunaName) {
        this.saunaName = saunaName;
    }

    public int getCo2() {
        return Co2;
    }

    public void setCo2(int co2) {
        Co2 = co2;
    }

    public int getHumidity() {
        return humidity;
    }

    public void setHumidity(int humidity) {
        this.humidity = humidity;
    }

    public int getTemperature() {
        return temperature;
    }

    public void setTemperature(int temperature) {
        this.temperature = temperature;
    }

    public Time getTime() {
        return time;
    }

    public void setTime(Time time) {
        this.time = time;
    }

}

And finally this is the get method in the API i am using to retrieve data:

  @GetMapping({"/getMeasurementBySaunaName/{name}"})
    private List<Measurements> getMeasurementsBySaunaName(@PathVariable String name){
        return measurementService.getMeasurementsBySaunaName(name);

    }

StackTrace:

W/System.err: com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: For input string: "20:36:00"
W/System.err:     at com.google.gson.internal.bind.TypeAdapters$11.read(TypeAdapters.java:306)
W/System.err:     at com.google.gson.internal.bind.TypeAdapters$11.read(TypeAdapters.java:296)
W/System.err:     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
W/System.err:     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
W/System.err:     at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41)
W/System.err:     at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
W/System.err:     at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
W/System.err:     at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:40)
W/System.err:     at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
W/System.err:     at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243)
W/System.err:     at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:153)
W/System.err:     at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/System.err:     at java.lang.Thread.run(Thread.java:920)
W/System.err: Caused by: java.lang.NumberFormatException: For input string: "20:36:00"
W/System.err:     at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
W/System.err:     at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
W/System.err:     at java.lang.Double.parseDouble(Double.java:538)
W/System.err:     at com.google.gson.stream.JsonReader.nextLong(JsonReader.java:964)
W/System.err:     at com.google.gson.internal.bind.TypeAdapters$11.read(TypeAdapters.java:304)
W/System.err:   ... 14 more

Anyone have any idea where it's going wrong? Thanks in advance!

  • 2
    Add the complete stacktrace please. An NumberFormatException is thrown, if you try to convert a non numeric or empty value To a number class – Jens Aug 10 '22 at 13:43
  • If you already eliminated non-numerical characters, look for the possibility of white space instead of numbers. – PM 77-1 Aug 10 '22 at 13:44
  • @Jens My apologise, I added the stacktrace now. – Matej Hackl Aug 10 '22 at 13:46
  • 4
    `20:36:00` is not numeric – Jens Aug 10 '22 at 13:47
  • I think you should change `public long time;` to `public String time;` – Jens Aug 10 '22 at 13:49
  • 1
    BTW: Take care of java naming conventions. Variable names should start with lower case character and be camelCase not snake_case – Jens Aug 10 '22 at 13:50
  • @Jens I get the same error even when it is a string. Could it be that the datatype in my database is messing something up? I have the time variable as "time without timezone" in my database. – Matej Hackl Aug 10 '22 at 13:53
  • 1
    I think `public LocalTime time;` would also work. – David Conrad Aug 10 '22 at 13:53
  • @DavidConrad I get an IllegalStateException when I change it to LocalTime. Also the linechart only takes float values for its x and y axis. – Matej Hackl Aug 10 '22 at 13:55
  • Yes, you would have to find some way of converting the time to a float, like maybe the decimal hours since midnight or something. – David Conrad Aug 10 '22 at 13:56
  • Than you have to recalculate the value later. But you only get a time from the json in a string format – Jens Aug 10 '22 at 13:56
  • @MatejHackl *Could it be that the datatype in my database is messing something up* I do not think so. you see in the error message that it comes from json parsing – Jens Aug 10 '22 at 14:06
  • @Jens Yes I know, I'm just extremely lost at this point. I've been trying to resolve this issue for the past 2 days. – Matej Hackl Aug 10 '22 at 14:10

1 Answers1

0

So I finally figured out where the issue was. I was receiving a string value of the time and it needed to be parsed into something that could be mapped. So I converted the string value of the time that I was receiving like this:

if (response.body() != null) {
                    for (int i = 0; i < response.body().size(); i++) {
                        String responseTime = response.body().get(i).time.substring(0,5);

                        float x = Float.parseFloat(responseTime.replace(":","."));
                        float y = response.body().get(i).temp;

                        if (y != 0) {
                            tempData.add(new Entry(x, y));
                        }
                        System.out.println("ITS GOING THROUGH THE THING");
                    }

Thank you to everyone that helped!