JavaWebStack / abstract-data

A library to abstractly represent structured data and convert it from and to several formats
Apache License 2.0
1 stars 0 forks source link

Adding type own type adapters for better enum support #1

Closed TimothyGillespie closed 3 years ago

TimothyGillespie commented 3 years ago

Is your feature request related to a problem? Please describe. Right now I have the use case where I wanna map a response from an API to an ENUM. The value I am getting looks like youtube#activityListResponse (YouTube API).

It does not seem possible to have the Enum map the way I want. And I don't necessarily want to design the Enum according to some technical limitations.

Describe the solution you'd like I think a solution could be to be able to register additional type adapters on the AbstractMapper which will be used in the gson() method. This would need to be propagated to the HTTPClient for my usage then.

Describe alternatives you've considered None

Additional context If the solution above makes sense please tell me, I will then post respective PRs.

TimothyGillespie commented 3 years ago

@JanHolger ?

JanHolger commented 3 years ago

At the moment we are using gson for mapping from and to pojo's. I'm planning to replace gson with an own mapping implementation though.

The current solution for your problem is using a gson type adapter. Good news for you is that we actually include a solution for your problem in AbstractData because i had the same issue before. Your enum needs to implement the GsonEnum interface and you need to annotate the enum fields with @TypeAdapter(GsonEnumAdapter.class)

TimothyGillespie commented 3 years ago

That's great. That should hopefully be easier then! Thanks, I'll try that.

TimothyGillespie commented 3 years ago

Since this might be difficult to follow and I had to ask to get it right on TeamSpeak:

The enum should look like this:

package eu.gillespie.youtubeapi.model;

import com.google.gson.annotations.JsonAdapter;
import eu.gillespie.youtubeapi.model.enums.APIResourceType;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.ToString;
import org.javawebstack.abstractdata.AbstractArray;
import org.javawebstack.abstractdata.AbstractMapper;
import org.javawebstack.abstractdata.util.GsonEnumAdapter;

import java.util.List;
import java.util.stream.Collectors;

@Getter
@ToString
public class Paginated {

    @JsonAdapter(GsonEnumAdapter.class)
    protected APIResourceType kind;
    protected String etag;
    protected String nextPageToken;
    protected String prevPageToken;
    protected PageInfo pageInfo;
    @Getter(AccessLevel.NONE)
    protected AbstractArray items;

    protected <T> List<T> _getItems(Class<T> type) {
        AbstractMapper mapper = new AbstractMapper();
        return items.stream().map(i -> mapper.fromAbstract(i, type)).collect(Collectors.toList());
    }

    @Getter
    private static class PageInfo {
        private int totalResults;
        private int resultsPerPage;
    }
}

and the class which uses the enum should look like this:

@Getter
@ToString
public class Paginated {

    @JsonAdapter(GsonEnumAdapter.class)
    protected APIResourceType kind;
    protected String etag;
    protected String nextPageToken;
    protected String prevPageToken;
    protected PageInfo pageInfo;
    @Getter(AccessLevel.NONE)
    protected AbstractArray items;

    protected <T> List<T> _getItems(Class<T> type) {
        AbstractMapper mapper = new AbstractMapper();
        return items.stream().map(i -> mapper.fromAbstract(i, type)).collect(Collectors.toList());
    }

    @Getter
    private static class PageInfo {
        private int totalResults;
        private int resultsPerPage;
    }
}

This example is taken from my, yet pretty immature, YouTube API Client.

To Note: The apiString contains the value returned by the api.