0

I have C# based web API. I am using Newtonsoft JSON to transfer the data.

    [HttpGet]
    [Route("birthdays/{month}")]
    public String GetBirthdays(int month)
    {
        List<BirthdayPropertiesDTO> dtoList = Mapper.Map<List<Property>, List<BirthdayPropertiesDTO>> (worker.PropertiesRepo.Get().ToList());
        foreach(BirthdayPropertiesDTO dto in dtoList)
        {
            dto.Birthdays = Mapper.Map<List<BirthdayList>, List<BirthdayDTO>>(worker.BirthdayRepo.Get(e => e.LocID == dto.ID && e.BirthMonth == month).ToList());
        }

        return JsonConvert.SerializeObject(dtoList);

    }

I have used a nearly identical approach (within the same API) for other endpoints, and have been able to successfully consume the data with JavaScript and PHP. However, the following Java code:

public class RESTClient {
    private static String END_POINT = "http://localhost:57263/locations/birthdays";

    public String sendRequest() {
        Gson gson = new Gson();
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        List<Property> propObj = new ArrayList<Property>();
        Type formType = new TypeToken<List<Property>>() {
        }.getType();

        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        String props = restTemplate.getForObject(
                MessageFormat.format("{0}/{1}", END_POINT, LocalDateTime.now().getMonthValue()), String.class, headers);

    propObj  = gson.fromJson(props, formType);

        return props;
    }
}

returns an exception:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 2 path $
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:224)
at com.google.gson.Gson.fromJson(Gson.java:888)
at com.google.gson.Gson.fromJson(Gson.java:853)
at com.google.gson.Gson.fromJson(Gson.java:802)
at com.google.gson.Gson.fromJson(Gson.java:774)
at com.midamcorp.birthdaylist.RESTClient.sendRequest(RESTClient.java:33)
at RESTTest.testRequest(RESTTest.java:17)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:539)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:761)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:461)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:207)
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 2 path $
    at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:385)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:213)
    ... 29 more

I have referenced similar questions (including this one), but have yet to find a resolution to my problem.

According to this tool, the JSON is valid.

"[{\"ID\":1,\"PropertyNumber\":\"1094\",\"Email\":\"email@email.com\",\"ManagerEmail\":\"email@email.com\",\"Birthdays\":[]},{\"ID\":2,\"PropertyNumber\":\"1175\",\"Email\":\"email@email.com\",\"ManagerEmail\":\"email@email.com\",\"Birthdays\":[]}

I also tried wrapping the object in another class (instead of using a List implementation), but received a similar exception.

    package com.midamcorp.birthdaylist;

import java.util.ArrayList;
import java.util.List;

public class BirthdayPropertyList {
private List<Property> properties = new ArrayList<Property>();

public List<Property> getProperties() {
    return properties;
}

public void setProperties(List<Property> properties) {
    this.properties = properties;
}

}

The Java object:

   public class Property {

private int id;
private String propertyNumber;
private String email;
private String managerEmail;
private List<Birthday> birthdays;

public String getPropertyNumber() {
    return propertyNumber;
}
public void setPropertyNumber(String propertyNumber) {
    this.propertyNumber = propertyNumber;
}
public String getStoreEmail() {
    return email;
}
public void setStoreEmail(String storeEmail) {
    this.email = storeEmail;
}
public String getManagerEmail() {
    return managerEmail;
}
public void setManagerEmail(String managerEmail) {
    this.managerEmail = managerEmail;
}
public List<Birthday> getBirthdays() {
    return birthdays;
}
public void setBirthdays(List<Birthday> birthdays) {
    this.birthdays = birthdays;
}
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}

}

The C# DTO:

    public class BirthdayPropertiesDTO
{
    public int ID { get; set; }
    public String PropertyNumber { get; set; }
    public String Email { get; set; }
    public String ManagerEmail { get; set; }
    public List<BirthdayDTO> Birthdays { get; set; }
}

Any advice would be appreciated.

KellyM
  • 2,472
  • 6
  • 46
  • 90
  • Thanks for pointing out the missing ID field, @azurefrog. I actually just forget. It did not resolve my present issue, but it might have been problematic down the road. EDIT: Yes, the JSON is actually very long, so that is just a partial snippet. Thanks. – KellyM Dec 20 '17 at 21:04
  • 2
    It looks like you are double-serializing your data. You are serializing it with Json.Net and then returning the JSON string from your controller method which Web API serializes again. That is why your JSON has all those backslashes in it. Try just returning the dtoList directly from your controller method. – Brian Rogers Dec 20 '17 at 21:08
  • @BrianRogers that actually worked. Thanks so much. However, what I am perplexed by is why the approach works fine using UniRest and JsonMapper in PHP, and axios and JSON.parse in Javascript? Are they just more forgiving/less strict than GSON? – KellyM Dec 20 '17 at 21:19
  • 1
    Without seeing the code, I couldn't say for sure. It's possible you had a similar situation in reverse-- perhaps the framework(s) you were using did automatic deserialization and you had a manual deserialization on top of it, so that undid the double-serialization on the server side. – Brian Rogers Dec 20 '17 at 21:22
  • So, duplicate of [JSON.NET Parser *seems* to be double serializing my objects](https://stackoverflow.com/q/25559179/3744182)? – dbc Dec 20 '17 at 22:18

0 Answers0