Jason Hodkinson
Jason Hodkinson

Reputation: 94

Sending data from Room persistence library using Retrofit

I have recently taken over a project that uses Android's Room persistence library as well as Retrofit. Unfortunately I am not very knowledgeable in either of these libraries.

I am currently trying to send through a JSON array of records saved with Room to an API using retrofit.

My entity looks like this:

@Entity(tableName = "location_table")
public class LocationEntity implements Serializable {

    @NonNull
    @PrimaryKey(autoGenerate = true)
    private int id;

    @SerializedName("job_id")
    @ColumnInfo(name = "job_id")
    @Expose
    private String job_id;

    @SerializedName("coordinates")
    @ColumnInfo(name = "coordinates")
    @Expose
    private String coordinates;

    @SerializedName("created_at")
    @ColumnInfo(name = "created_at")
    @Expose
    private String created_at;

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

    public String getJob_id() { return job_id; }
    public void setJob_id(String job_id) { this.job_id = job_id; }

    public String getCoordinates() { return coordinates; }
    public void setCoordinates(String coordinates) { this.coordinates = coordinates; }

    public String getCreated_at() { return created_at; }
    public void setCreated_at(String created_at) { this.created_at = created_at; }

    @Ignore
    public LocationEntity() {
        // DATA TO IGNORE
    }

    public LocationEntity(String job_id, String coordinates, String created_at) {
        this.job_id = job_id;
        this.coordinates = coordinates;
        this.created_at = created_at;
    }
}

In my DOA I have:

@Dao
public interface LocationDAO {
    @Query("SELECT * from location_table ORDER BY id ASC")
    List<LocationEntity> getAll();
}

And the Repository has:

public class LocationRepository {

    private static BudtrackDatabase budtrackDatabase;
    public LocationRepository(Context context) {
        budtrackDatabase = Room.databaseBuilder(context, BudtrackDatabase.class, AppConstants.DATABASE_NAME).build();
    }

    public static List<LocationEntity> getLocations() {
        return budtrackDatabase.locationDAO().getAll();
    }
}

My request:

public interface LocationRequest {

    /**
     * Send through multiple locations
     * @param token
     * @param coordinates
     */
    @FormUrlEncoded
    @POST("api/coordinates")
    Call<String> sendLocations(@Field("token") String token,
                               @Field("coordinates[]") List<LocationEntity> coordinates);
}

I then try to send the data using retrofit like so:

String token = "12345";
List<LocationEntity> locations = locationRepository.getLocations();

Call<String> callLocation = sendLocationService.sendLocations(token, locations);
callLocation.enqueue(new Callback<String>() {
    @Override
    public void onResponse(Call<String> call, Response<String> response) {
        if (response.isSuccessful()) {
            // Logic for success
        } else {
            try {
                JSONObject jObjError = new JSONObject(response.errorBody().string());
                Toast.makeText(activity, jObjError.getString("message"), Toast.LENGTH_LONG).show();
            } catch (Exception e) {
                Toast.makeText(activity, e.getMessage(), Toast.LENGTH_LONG).show();
            }
        }
    }

    @Override
    public void onFailure(Call<String> call, Throwable t) {
        Log.e("Failed To Send Location", t.getMessage());
    }
});

I then get the data on the API side like so:

"coordinates" : [ 
        "com.yard8.budtrack.data.location.LocationEntity@4d87c17", 
        "com.yard8.budtrack.data.location.LocationEntity@6c60804", 
        "com.yard8.budtrack.data.location.LocationEntity@fdad1ed", 
        "com.yard8.budtrack.data.location.LocationEntity@66fc822", 
        "com.yard8.budtrack.data.location.LocationEntity@8dec2b3", 
        "com.yard8.budtrack.data.location.LocationEntity@f9da070", 
];

What is the correct way of sending through the data so that it comes through as a JSON array?

Upvotes: 0

Views: 1301

Answers (2)

Jason Hodkinson
Jason Hodkinson

Reputation: 94

I may have been trying to over-complicate things and all I needed to do was change

@Field("coordinates[]") List<LocationEntity> coordinates

to

@Field("coordinates") String coordinates

And then before the call use...

Gson gson = new Gson();
String locations = gson.toJson(locationRepository.getLocations());

...and pass it through as my second parameter.

Call<String> callLocation = sendLocationService.sendLocations(token, locations);

I really thought this would only work on a single object and not a list of them because of the way I had been receiving the data server side.

Upvotes: 2

Nanda Z
Nanda Z

Reputation: 1876

Have you try something like this

1. Creating new Class

class ParentEntity{

        private List<LocationEntity> locationEntities;

        public List<LocationEntity> getLocationEntities() {
            return locationEntities;
        }

        public void setLocationEntities(List<LocationEntity> locationEntities) {
            this.locationEntities = locationEntities;
        }
    }

2. Then in your response retrofit

// ....... //
@Override
public void onResponse(Call<String> call, Response<String> response) {
    if (response.isSuccessful()) {
        // Logic for success
        ParentEntity readObj = response.body();
        List<LocationEntity> locations = readObj.getLocationEntities();

        // DO SOMETHING YOU WANT

    } else {
        try {
            JSONObject jObjError = new JSONObject(response.errorBody().string());
            Toast.makeText(activity, jObjError.getString("message"), Toast.LENGTH_LONG).show();
        } catch (Exception e) {
            Toast.makeText(activity, e.getMessage(), Toast.LENGTH_LONG).show();
        }
    }
}
// ....... //

UPDATE try using @Body, probably the structure like below 1. Create new Class

class ParentEntity{

        private LocationEntity location;
        private String token;

        public LocationEntity getLocation() {
            return location;
        }

        public void setLocation(LocationEntity location) {
            this.location = location;
        }

        public String getToken() {
            return token;
        }

        public void setToken(String token) {
            this.token = token;
        }
    }
  1. Use Body instead of Field, also without @FormUrlEncoded

    @POST("/") Call sendLocations(@Body ParentEntity parentEntity);

Upvotes: 0

Related Questions