I want to interact with a RESTful webservice that responds only in JSON.
Any successful response from the server has this syntax:
{
"code": int code,
"data": object or list of objects
}
while on error response:
{
"code": int code,
"error": string,
"details": string
}
So I made two classes in my Android project like this (for GSON reflection):
public class ErrorEntity {
private String details;
private String error;
private int code;
public ErrorEntity() {
// Stub constructor
}
public String getDetails() {
return details;
}
public String getError() {
return error;
}
public int getCode() {
return code;
}
}
For a successful response I made a generic because I don't want to parse JSON data on overridden parseNetworkResponse:
public class SuccessfulEntity<T> {
private T data;
private int code;
public SuccessfulEntity() {
// Stub content
}
public T getData() {
return data;
}
public int getCode() {
return code;
}
}
Now, because my RESTful server requires some custom headers, I need to make a Request subclass, but I don't know from which class I need to inherit.
I saw this question: Send POST request with JSON data using Volley and though to do something like that.
Basically, I want to make a new class (VolleyRestClient) which has GET, POST, DELETE methods and API routings, and with this class make all requests I need to do.
Methods of this class need to make a new custom request and parse new objects response like SuccessfulEntity and ErrorEntity, and then parsing data in service/thread that make the VolleyRestClient call.
How can I do that?
After a long fight with generics and type erasure, I finally did it.
So I'm posting this for whoever has the same issue like me and needs a solution without freaking out.
My ErrorEntity and my SuccessfulEntity are still the same, but I created a new interface called RepositoryListener, like this:
public interface RepositoryListener {
public abstract void onErrorResponse(int code, String details);
public abstract void onSuccessfulResponse(int code, Object obj);
public abstract void onSuccessfulResponse2(int code, List<Object> obj);
}
Then I made a class, VolleyRestClient, like this:
public class VolleyRestClient extends RestClient {
private final DefaultRetryPolicy mRetryPolicy;
private final RequestQueue mQueue;
private final Gson gson = new Gson();
public VolleyRestClient(Context context) {
// Default retry policy
mRetryPolicy = new DefaultRetryPolicy(2000, 3, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
mQueue = Volley.newRequestQueue(context);
}
public RequestQueue getQueue() {
// Method to push requests for image download
return mQueue;
}
#Override
public void GET(boolean obj, boolean needAuth, String url, Type type,
RepositoryListener listener) {
// Choose which listener to construct
Response.Listener<myResponse> mListener = obj ?
// This uses objects
makeSuccessfulListener(listener, type) :
// This uses list of objects
makeSuccessfulListener2(listener, type);
myRequest mRequest =
new myRequest(Request.Method.GET, needAuth, url,
mListener, makeErrorListener(listener));
mRequest.setRetryPolicy(mRetryPolicy);
mQueue.add(mRequest);
}
#Override
public void POST(boolean needAuth, String url, String body, Type type, RepositoryListener listener) {
myRequest mRequest = new myRequest(Request.Method.POST, needAuth, url, body,
makeSuccessfulListener(listener, type), makeErrorListener(listener));
mRequest.setRetryPolicy(mRetryPolicy);
mQueue.add(mRequest);
}
#Override
public void DELETE(boolean needAuth, String url, Type type, RepositoryListener listener) {
myRequest mRequest =
new myRequest(Request.Method.DELETE, needAuth, url,
makeSuccessfulListener(listener, type), makeErrorListener(listener));
mRequest.setRetryPolicy(mRetryPolicy);
mQueue.add(mRequest);
}
private Response.Listener<myRequest> makeSuccessfulListener
(final RepositoryListener listener, final Type type) {
// TODO: test this method and implement lists
if (listener == null) {
return null;
} else {
return new Response.Listener<myRequest>() {
#Override
public void onResponse(myRequest response) {
SuccessfulEntity<Object> obj = gson.fromJson(response.getBody(), type);
listener.onSuccessfulResponse(response.getCode(), obj.getData());
}
};
}
}
private Response.Listener<myRequest> makeSuccessfulListener2
(final RepositoryListener listener, final Type type) {
// TODO: test lists
if (listener == null) {
return null;
} else {
return new Response.Listener<myRequest>() {
#Override
public void onResponse(myReqyest response) {
SuccessfulEntity<List<Object>> obj = gson.fromJson(response.getBody(), type);
listener.onSuccessfulResponse2(response.getCode(), obj.getData());
}
};
}
}
private Response.ErrorListener makeErrorListener(final RepositoryListener listener) {
return new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
try {
String jError = new String(error.networkResponse.data);
ErrorEntity mError = gson.fromJson(jError, ErrorEntity.class);
// Invoke listener closure
listener.onErrorResponse(error.networkResponse.statusCode, mError.getDetails());
} catch (Exception e) {
listener.onErrorResponse(404, e.getMessage());
}
}
};
}
}
This is very dependant by my needs, but I'll explain the general concept.
So I have a custom request, as explained in my question, and I want to parse it to the correct data type.
To be more specific, I could have a JSONArray data only on GET requests (paginated elements, etc...) so I need to find a way to distinguish between this two cases (of course, I know in which cases I'll get a List or an Object).
We cannot simply create POJO from Json within a generic class using its type (because Java Type Erasure), so we need object type upfront.
But what we can do is:
in our custom request, on parseNetworkResponse, do something like that:
#Override
protected Response<myResponse> parseNetworkResponse(NetworkResponse response) {
try {
// Using server charset
myResponse mResponse = new myResponse();
mResponse.setCode(response.statusCode);
mResponse.setBody(new String(response.data,
HttpHeaderParser.parseCharset(response.headers)));
// Return new response
return Response.success(mResponse, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
// Normally use 'utf-8'
return Response.error(new ParseError(e));
}
}
In other words, copy the raw string response body onto a new object myResponse;
Response body will be eventually parsed in VolleyRestClient with the appropriate type passed as a GET/DELETE/POST argument;
makeSuccessfulListener and makeSuccessfulListener2 construct a Response.Listener from a RepositoryListener, which has 3 methods to override: onSuccessfulResponse for objects data, onSuccessfulResponse2 for list of objects data, onErrorResponse for 4XX/5XX errors;
Our data object/list will be parsed to more generics type (List and Object) and then passed to our custom listener RepositoryListener.
A full example for this approach:
public void getNewLogin(String nickname, String password,
final TextView author, final TextView title, final TextView text) {
String json =
(new StringBuilder()
.append("{ \"nickname\": \"")
.append(nickname)
.append("\", \"password\": \"")
.append(password)
.append("\" }")).toString();
mRest.POST(false, "http://192.168.0.104:8000/api/session", json,
new TypeToken<SuccessfulEntity<Login>>(){}.getType(),
new RepositoryListener() {
#Override
public void onSuccessfulResponse2(int code, List<Object> obj) {
// Nothing happens here
}
#Override
public void onSuccessfulResponse(int code, Object obj) {
UserSession mInstance = UserSession.getInstance(null);
Login newLogin = (Login) obj;
title.setText(newLogin.getToken());
mInstance.setToken(newLogin.getToken());
Log.i("onSuccessfulResponse", mInstance.getToken());
Log.i("onSuccessfulResponse", mInstance.getmAuthorizationToken());
if (newLogin.getUser() != null) {
author.setText(newLogin.getUser().getNickname());
text.setText(newLogin.getUser().getUniversity());
}
}
#Override
public void onErrorResponse(int code, String error) {
Log.i("onErrorResponse", error);
}
});
mRest is a VolleyRestClient object, which performs a POST request to that address with Type constructed by Gson TypeToken (remember, our body is a SuccessfulEntity).
Since we'll have an Object data for sure, we'll just override onSuccessfulResponse, cast data object to the same type T of SuccessfulEntity used in TypeToken, and do our dirty work.
I don't know if I was clear, this approach works, if some of you needs some clarification, just ask :)
Related
How can I parse this using Retrofit?I'm getting the error
BEGIN_OBJECT but was BEGIN_ARRAY
The Json is below and it contain a results array object, that have one array object which is null and objects of information. It seems like that array of null is the problem, and I need some help to solve this if its possible to be solved?
{
"error": "OK",
"limit": 100,
"offset": 0,
"number_of_page_results": 16,
"number_of_total_results": "16",
"status_code": 1,
"results": [
[],
{
"api_detail_url"............
Model class:
public class Response {
#SerializedName("results")
List<IssuesResults> resultList;
public Response(ArrayList<IssuesResults> resultList) {
this.resultList = resultList;
}
public List<IssuesResults> getResultList() {
return resultList;
}
}
Api
#GET("promos/")
Call<Response> getPromos(#Query("api_key") String API_KEY,
#Query("format") String format);
Repo
public MutableLiveData<List<IssuesResults>> getPromos() {
callApi.getPromos(API_KEY,"json").enqueue(new Callback<Response>() {
#Override
public void onResponse(Call<Response> call,
retrofit2.Response<Response> response) {
promosMutableData.setValue(response.body().getResultList());
}
#Override
public void onFailure(Call<Response> call, Throwable t) {
Log.d("PROMOS", "onFailure: " + t);
}
});
return promosMutableData;
}
I assume you use Gson with default settings. Your problem is that you expect a list of IssuesResults but it contains this extra array which means it is - by default - serializable only as a list of objects which then would be one array and N maps as items.
For this kind of stuff you need some custom handling and I present here one option which is JsonDeserializer. I requires few changes to make things a bit easier ( (they are not all necessities for other approaches but for this solution i use these ones) ). First instead of inline typed List implement class like:
#SuppressWarnings("serial")
public static class ListIssuesResults extends ArrayList<IssuesResults> {
// This override is not needed if you do not mind null values in your resulting list
#Override
public boolean add(IssuesResults e) {
if (null != e) {
return super.add(e);
}
return false;
}
}
The change the Response like:
public static class Response {
#SerializedName("results")
private ListIssuesResults resultList;
// other stuff
}
Then the actual custom JsonDeserializer:
public static class IssuesResultsDeserializer implements JsonDeserializer<IssuesResults> {
// this you need to not to cause recursion and stack overflow
private static final Gson GSON = new Gson();
#Override
public IssuesResults deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context)
throws JsonParseException {
// this is the trick. if it fails to serialize stuff like [] jsut return null
try {
return GSON.fromJson(json, typeOfT);
} catch (Exception ise) {
return null;
}
}
}
To use custom deserializer you need to register it like:
new GsonBuilder().registerTypeAdapter(IssuesResults.class,
new IssuesResultsDeserializer()).create();
This has to be done in Retrofit client building phase, like in this: How to register custom TypeAdapter or JsonDeserializer with Gson in Retrofit?
My question is about the possibility to use RxJava for Android to manipulate data from a Retrofit call.
I've just started to use these libraries, so if my questions are trivial, please be patient.
This is my scenario.
I have a json returned from the server that looks like this
{ <--- ObjectResponse
higher_level: {
data: [
{
...
some fields,
some inner object: {
....
},
other fields
}, <----- obj 1
....,
{
....
}<---- obj n
]<-- array of SingleObjects
}
} <--- whole ObjectResponse
I've already have retrofit get this response and parsed in a ObjectResponse. Parsing this object, I can obtain a List that I can pass as usual to my RecyclerView Adapter.
So retrofit returned the ObjectResponse which is the model for the entire server answer, and in the retrofit callback I manipulate ObjectResponse to extract my List to be then passed to my adapter.
Right now, I have something like this
Call<ObjectResponse> call = apiInterface.getMyWholeObject();
call.enqueue(new Callback<ObjectResponse>() {
#Override
public void onResponse(Call<ObjectResponse> call, Response<ObjectResponse> response) {
//various manipulation based on response.body() that in the ends
// lead to a List<SingleObject>
mView.sendToAdapter(listSingleObject)
}
#Override
public void onFailure(Call<ObjectResponse> call,
Throwable t) {
t.printStackTrace();
}
});
My question is:
Is there a way to obtain from retrofit an Observable that can ultimate lead me to emit the list of SingleObject (and manipulate it) without have to manipulate ObjectResponse as I would do in the retrofit callback? Or should I have to stick with the retrofit callback and only after obatin List I can manipulate with RxJava just before feed this list to my Adapter?
I'd like to obtain something like this
apiInterface
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<SingleObject>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<Post> posts) {
mView.sendToAdapter(listSingleObject)
}
});
Retrofit converter factories solve that issue very nicely.
Jake Wharton talks about "envelope" objects in his "Making Retrofit Work For You" talk and points out how that can be solved.
Having defined an envelope class - a class with some extra fields that you do not care about:
public class Envelope<T> {
Meta meta;
List<Notification> notifications;
T response;
}
In this POJO fields meta and List<Notification> are being returned from the backend, but in the context of android app they are not interesting to us. Assume, that the real value that you need from the response is field named response, which might be any object (because it's generic).
Particularly in your example the POJO structure would be like this:
public class OriginalResponse {
HigherLevel higher_level;
}
public class HigherLevel {
Data data;
}
public class Data {
List<ActualData> list;
}
You have to implement your custom Converter.Factory:
public class EnvelopingConverter extends Converter.Factory {
#Nullable
#Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
Type envelopedType = TypeToken.getParameterized(Envelope.class, type).getType();
Converter<ResponseBody, Envelope<?>> delegate = retrofit.nextResponseBodyConverter(this, envelopedType, annotations);
return body -> {
Envelope<?> envelope = delegate.convert(body);
// Here return the object that you actually are interested
// in your example it would be:
// originalResponse = delegate.convert(body);
// return originalResponse.higher_level.data.list;
return envelope.response;
};
}
}
Add this converter to your retrofit builder:
new Retrofit.Builder()
...
.addConverterFactory(new EnvelopingConverter())
...
Then in your retrofit api interface instead of returning Single<OriginalResponse> return Single<List<ActualData>> directly:
interface Service {
#GET(...)
Single<List<ActualData>> getFoo();
}
Typical implementation in Kotlin:
class EnvelopeConverterFactory : Converter.Factory() {
override fun responseBodyConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<ResponseBody, *>? {
val envelopedType: Type = TypeToken.getParameterized(ParentObject::class.java, type).type
val delegate: Converter<ResponseBody, ParentObject> =
retrofit.nextResponseBodyConverter(this, envelopedType, annotations)
return Converter<ResponseBody, ChildObject> { body -> delegate.convert(body)?.childObject }
}
}
As far as I know, there's no way to do it. For best practice, you should create a Facade layer (maybe an ApiManager class) to manage all your APIs. In that case, you can use map/flatMap to map your ObjectResponse to SingleObject like:
public Observable<List<SingleObject>> getSingleObjects(){
return ServiceGenerator.getApiMethods().getObjectResponse.map(new Function<ObjectResponse, List<SingleObject>>() {
#Override
public List<SingleObject> apply(ObjectResponse response) throws Exception {
return reponse.getListSingleObjects();
}
})
}
After some days, I can post my own solution.
It is inspired by the idea suggested by azizbekian.
The center idea is on the Envelope class, which I've express using retrofit annotation to be sure it would adapt to different JSON response from server, parsing the
higher_level: {
data: [
mid_level: { .. },
...
]
}
structure that I've already explained in my original post
public class WrapperResponse<T> {
#SerializedName(value="higher_level", alternate={"mid_level", "other"})
#Expose
DataResponse<T> data;
public DataResponse<T> getData() {
return data;
}
public void setData(DataResponse<T> data) {
this.data = data;
}
}
The focus here is in the parameters of SerializedName, where I specify all the possible JSON objects name that appear in my server response.
Then I have
public class UnwrapConverterFactory extends Converter.Factory {
private GsonConverterFactory factory;
public UnwrapConverterFactory(GsonConverterFactory factory) {
this.factory = factory;
}
#Override
public Converter<ResponseBody, ?> responseBodyConverter(final Type type,
Annotation[] annotations, Retrofit retrofit) {
Type wrappedType = new ParameterizedType() {
#Override
public Type[] getActualTypeArguments() {
return new Type[] {type};
}
#Override
public Type getOwnerType() {
return null;
}
#Override
public Type getRawType() {
return WrapperResponse.class;
}
};
Converter<ResponseBody, ?> gsonConverter = factory
.responseBodyConverter(wrappedType, annotations, retrofit);
return new WrapperResponseBodyConverter(gsonConverter);
}
}
and
public class WrapperResponseBodyConverter<T>
implements Converter<ResponseBody, T> {
private Converter<ResponseBody, WrapperResponse<T>> converter;
public WrapperResponseBodyConverter(Converter<ResponseBody,
WrapperResponse<T>> converter) {
this.converter = converter;
}
#Override
public T convert(ResponseBody value) throws IOException {
WrapperResponse<T> response = converter.convert(value);
return response.getData().getData();
}
}
Used in my Retrofit Module (dagger2) to ensure that my Retrofit client unwrap any answer from server using the generic WrapperResponse and, in the end, I can write Retrofit method as
#GET("locations")
Observable<List<Location>> getLocation();
where List is exactly the result I wanted to obtain: a list of objects straight from Retrofit response, that I can further elaborate with RxJava.
Thanks all.
In my application, most of the JSON that I receive from the server have the following structure:
{
"IsError":false,
"Result":{ "key1":"value", "key2":"value", ... }
}
I've followed #fernandospr 's suggestion in my original question about GSON and tried using generics to avoid writing two objects (Response and Result) per JSON and having a generic Response Object which would adapt to any kind of Result; as:
public class GenericResponse<T> {
#SerializedName("IsError")
private boolean isError;
#SerializedName("Result")
private T result;
public boolean isError() {
return isError;
}
public T result() {
return result;
}
}
Where I would indicate a specific Object when performing a call. The structure of the Profile Object, replacing the generic T is:
public class Profile {
#SerializedName("UserName")
private String userName;
#SerializedName("Stuff")
private boolean stuff;
#SerializedName("ListOfStuff")
private List<String> listOfStuff = new ArrayList<String>();
...
}
And then I perform the synchronous call like this:
Call<GenericResponse<Profile>> call = Api.getProfile(username);
try {
GenericResponse<Profile> response = call.execute().body();
} catch (IOException e) {
MUtils.logException(e);
}
Then the .body() method returns a null. I've debugged the .body() method and it seems to be working internally but the parsing doesn't work. I have reasons to believe parsing is the problem because with this simpler JSON object (doesn't require a separate Result Object) in another call .body() returns the object as it should:
public class ConfirmPasswordResponse {
#SerializedName("isError")
private boolean isError;
#SerializedName("Result")
private boolean Result;
public boolean isError() {
return isError;
}
public boolean result() {
return Result;
}
}
As per an use-case, this is what we do:
Expose multiple Async service APIs with different arguments (ex. InputObject1, InputObject2 etc.).
Client calls these APIs with proper input type and we send response back to client and push input object in a queue (ex. SQS) in JSON form (using Gson).
Another poller, keeps on polling the queue and receives messages from the queue. On receiving the message, poller has to do the task as per inputObject type.
There are two places my code could look dirty:
a. How to check the type of object on receiving from the queue? This would be in JSON format and I will have to convert JSON back to object. It will belong to one of the multiple potential objects.
b. Once type is known, how to call class responsible to handle that object?
What could be the optimal design for this use-case?
For a), one option is to create a `RequestWrapper` containing all the objects and populating the one this message belongs to.
Couple of ways I can think for b) are as following:
1. Add another parameter to the object and pass it to queue. Use this parameter to identify API called.
2. Use `instanceof` to get exact requestObject using multiple if-else and do the needful.
Though, these don't seem very neat to me. Any better suggestions?
==Edit==
#A4L
No, they don't share any common interface (at least, as of now).
Yes, we can modify these objects in the start (if that's what you mean by "implementation"). Since, we can change this, I can make them share a common interface, if required.
Thanks,
I would suggest to introduce at least one new interfaces QueueTaskAble which will be implement by your input objects and a second - optional, could simply be java.lang.Runnable - which then executes the Task with some sort of run or execute method.
Here is how it could look like:
interface QueueTaskAble {
Runnable getQueueTask();
}
class InputObjectFooQueueTask implements Runnable {
#Override
public void run() {
// TODO Auto-generated method stub
}
}
class InputObjectFooImpl implements QueueTaskAble {
#Override
public Runnable getQueueTask() {
return new InputObjectFooQueueTask();
}
}
void processQueueInputObject(QueueTaskAble queueObject) {
queueObject.getQueueTask().run();
}
EDIT
Unfortunately it is not possible to natively deserialize as interface using Gson. To be able to do so you need to implement a type adapter which you can pass to GsonBuilder#registerTypeAdapter so that your object are properly serialized and deserialized.
Here is how you could go about it:
The type adapter
public class GenericGsonTypeAdapter<T> implements JsonSerializer<T>,
JsonDeserializer<T> {
#Override
public JsonElement serialize(T src, Type typeOfSrc,
JsonSerializationContext context) {
JsonObject jo = new JsonObject();
jo.addProperty("className", src.getClass().getName());
jo.add("jsonData", context.serialize(src));
return jo;
}
#Override
public T deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
T obj = null;
if(json instanceof JsonObject) {
JsonObject jo = (JsonObject) json;
JsonElement jeJson = jo.get("jsonData");
if(jeJson != null) {
JsonElement jeClassName = jo.get("className");
try {
obj = context.deserialize(json,
Class.forName(jeClassName.getAsString()));
} catch (ClassNotFoundException e) {
throw new JsonParseException(e);
}
}
}
return obj;
}
}
A custom Gson builder (unfortunately GsonBuilder is final and thus cannot be extended, hence as static final member)
public class InputObjectGsonBuilder {
private final static GsonBuilder gb;
static {
gb = new GsonBuilder();
gb.registerTypeAdapter(QueueTaskAble.class,
new GenericGsonTypeAdapter<QueueTaskAble>());
}
public Gson create() {
return gb.create();
}
}
A sample queue
public class InputObjectGsonQueue {
private Queue<String> queue = new ArrayDeque<>();
public boolean pushInputObject(String json) {
return queue.offer(json);
}
public void processQueue() {
InputObjectGsonBuilder gb = new InputObjectGsonBuilder();
String json;
while(null != (json = queue.poll())) {
QueueTaskAble queueTaskAble = gb.create().fromJson(json,
QueueTaskAble.class);
processQueueInputObject(queueTaskAble);
}
}
private void processQueueInputObject(QueueTaskAble queueObject) {
queueObject.getQueueTask().run();
// or for asynchronous processing
// new Thread(queueObject.getQueueTask()).start();
}
}
Some input objects and tasks implementations
public class InputObjectFooImpl implements QueueTaskAble {
#Override
public Runnable getQueueTask() {
return new InputObjectFooTaksImpl();
}
}
public class InputObjectBarImpl implements QueueTaskAble {
#Override
public Runnable getQueueTask() {
return new InputObjectBarTaksImpl();
}
}
public class InputObjectFooTaksImpl implements Runnable {
#Override
public void run() {
System.out.println("Foo!");
}
}
public class InputObjectBarTaksImpl implements Runnable {
#Override
public void run() {
System.out.println("Bar!");
}
}
And finally a sample application
public class App {
public static void main(String... args) {
InputObjectGsonBuilder gb = new InputObjectGsonBuilder();
InputObjectGsonQueue gq = new InputObjectGsonQueue();
gq.pushInputObject(gb.create().toJson(new InputObjectFooImpl(),
QueueTaskAble.class));
gq.pushInputObject(gb.create().toJson(new InputObjectBarImpl(),
QueueTaskAble.class));
gq.processQueue();
}
}
Output
Foo!
Bar!
I am facing problem while deserializing to below entity using Javascript Serializer. Please help
JSON String:
{"AccountNo":0,"EmailAddress":"test#gmail.com","Destination_Prefernce":[{"Value":"Test Data"}]}
Java Code
public class EMailPreferenceEntity
{
private int _accountNo;
private string emailAddress;
private DestinationPreferences _destinationPrefernce = new DestinationPreferences();
public int AccountNo
{
get { return _accountNo; }
set { _accountNo = value; }
}
public string EmailAddress
{
get { return emailAddress; }
set { emailAddress = value; }
}
public DestinationPreferences Destination_Prefernce
{
get { return _destinationPrefernce; }
set { _destinationPrefernce = value; }
}
}
Handler File:
public class AjaxHandler : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest (HttpContext context) {
string jsData = context.Request["Data"];
if (!string.IsNullOrEmpty(jsData))
{
JavaScriptSerializer ser = new JavaScriptSerializer();
EMailPreferenceEntity jsEntity = ser.Deserialize<EMailPreferenceEntity>(jsData);
}
}
Type erasure means your List will just become List after compilation so, when your http request arrives, it will try to deserialize List, and probably won't hit whatever you registered for List.
I'm not sure how your serializer handles it, but in Gson's case, you create a TypeToken out of the generic, so that the connection between type and serializer doesn't get lost after compilation.