I am trying to parse a json string back to a Java object with gson. But I keep getting the above mentioned error:
Expected BEGIN_OBJECT but was STRING.
I saw there are some SO questions with this error, but none of them seems to be applicable to my situation.
My Java Code is the following:
Gson gson = new Gson();
Payment p = gson.fromJson(paymentJson, Payment.class);
where paymentJson is the JSON-String of a Payment object, which i get over an http post.
The Json-String Im using to test it is the following:
{
"creationDate": "2013-04-10T09:59:45.890+02:00",
"beneficiary": "Heat Hot Sauces",
"amount": 31.54,
"ibanSender": "CH190020600000DEMO303",
"paymentType": "ACCOUNT_TO_ACCOUNT",
"executionDate": "2013-04-10",
"fees": 0,
"ibanReceiver": "CH730020600000DEMO301",
"status": {
"code": "PENDING"
},
"currency": "CHF",
"description": "Sudden Death Sauce",
"id": "25202",
"total": 31.54
}
And I checked the validity of the JSON with JsonLint, its valid json.
I know the other side which sends me the json data over http uses also GSON and the same class "Payment", but I'm not able/allowed to change the code there.
The Payment class looks like this:
public class Payment {
private String id;
private PaymentType paymentType;
private PaymentCategory paymentCategory;
private String ibanSender;
private LocalDate executionDate;
private DateTime creationDate;
private String currency;
private Double amount;
private Double fees;
private PaymentStatus status;
private String description;
private Double total;
// attributes which identifiers the beneficiary of the payment
private String ibanReceiver;
private String accountNumber;
private String swift;
private String referenceNumber;
private PaymentFeesChargingCode feesCharging;
private String beneficiary;
// the following 5 beneficiary fields can be used for address (beneficiary_5
// should be used for country)
private String beneficiary_1;
private String beneficiary_2;
private String beneficiary_3;
private String beneficiary_4;
private String beneficiary_5; // country
// the reference to the StandingOrder which created this payment, or null
private String standingOrderId;
public Payment() {
super();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public PaymentType getPaymentType() {
return paymentType;
}
public void setPaymentType(PaymentType paymentType) {
this.paymentType = paymentType;
}
public String getIbanSender() {
return ibanSender;
}
public void setIbanSender(String ibanSender) {
this.ibanSender = ibanSender;
}
public LocalDate getExecutionDate() {
return executionDate;
}
public void setExecutionDate(LocalDate executionDate) {
this.executionDate = executionDate;
}
public DateTime getCreationDate() {
return creationDate;
}
public void setCreationDate(DateTime creationDate) {
this.creationDate = creationDate;
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
public Double getFees() {
return fees;
}
public void setFees(Double fees) {
this.fees = fees;
}
public PaymentStatus getStatus() {
return status;
}
public void setStatus(PaymentStatus status) {
this.status = status;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getTotal() {
return total;
}
public void setTotal(Double total) {
this.total = total;
}
public String getIbanReceiver() {
return ibanReceiver;
}
public void setIbanReceiver(String ibanReceiver) {
this.ibanReceiver = ibanReceiver;
}
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public String getSwift() {
return swift;
}
public void setSwift(String swift) {
this.swift = swift;
}
public String getReferenceNumber() {
return referenceNumber;
}
public void setReferenceNumber(String referenceNumber) {
this.referenceNumber = referenceNumber;
}
public PaymentFeesChargingCode getFeesCharging() {
return feesCharging;
}
public void setFeesCharging(PaymentFeesChargingCode feesCharging) {
this.feesCharging = feesCharging;
}
public String getBeneficiary() {
return beneficiary;
}
public void setBeneficiary(String beneficiary) {
this.beneficiary = beneficiary;
}
public String getBeneficiary_1() {
return beneficiary_1;
}
public void setBeneficiary_1(String beneficiary_1) {
this.beneficiary_1 = beneficiary_1;
}
public String getBeneficiary_2() {
return beneficiary_2;
}
public void setBeneficiary_2(String beneficiary_2) {
this.beneficiary_2 = beneficiary_2;
}
public String getBeneficiary_3() {
return beneficiary_3;
}
public void setBeneficiary_3(String beneficiary_3) {
this.beneficiary_3 = beneficiary_3;
}
public String getBeneficiary_4() {
return beneficiary_4;
}
public void setBeneficiary_4(String beneficiary_4) {
this.beneficiary_4 = beneficiary_4;
}
public String getBeneficiary_5() {
return beneficiary_5;
}
public void setBeneficiary_5(String beneficiary_5) {
this.beneficiary_5 = beneficiary_5;
}
@Override
public String toString() {
return "Payment [id=" + id + ", ibanSender=" + ibanSender + ", ibanReceiver=" + ibanReceiver + ", beneficiary=" + beneficiary + ", executionDate=" + executionDate + ", creationDate=" + creationDate + ", currency=" + currency + ", amount=" + amount + ", fees=" + fees + ", status=" + status + ", description=" + description + ", total=" + total + "]";
}
public PaymentCategory getPaymentCategory() {
return paymentCategory;
}
public void setPaymentCategory(PaymentCategory paymentCategory) {
this.paymentCategory = paymentCategory;
}
public String getStandingOrderId() {
return standingOrderId;
}
public void setStandingOrderId(String standingOrderId) {
this.standingOrderId = standingOrderId;
}
}
EDIT: here is the stack-trace:
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 48
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176)
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:93)
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172)
com.google.gson.Gson.fromJson(Gson.java:795)
com.google.gson.Gson.fromJson(Gson.java:761)
com.google.gson.Gson.fromJson(Gson.java:710)
com.google.gson.Gson.fromJson(Gson.java:682)
ch.ti8m.bank.payment.scanbuy.controller.ScanAndBuyController.preparePayment(ScanAndBuyController.java:58)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:746)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:687)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:915)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:822)
javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:796)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:180)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
java.lang.Thread.run(Thread.java:722)
Does anyone have an idea why I'm getting that error message?
Thanks in advance
GSON fails to parse the value of the creationDate field because it does not know how to handle Joda-Time DateTime objects.
Try to register a type adapter for this class using GsonBuilder's registerTypeAdapter method.
Gson gson = new GsonBuilder().registerTypeAdapter(DateTime.class, new JsonDeserializer<DateTime>() {
@Override
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return new DateTime(json.getAsString());
}
}).create();
I have implemented a slightly different approach, since in my case I have problems both serializing and deserializing attributes of java.time.LocalDate in my Spring Boot project:
@Configuration
@EnableWebMvc
public class ApplicationConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
GsonHttpMessageConverter gsonConverter = new GsonHttpMessageConverter();
gsonConverter.setGson(gson());
converters.add(gsonConverter);
}
@Bean
public Gson gson() {
return new GsonBuilder()
.serializeNulls()
.registerTypeAdapter(LocalDate.class,
(JsonSerializer<LocalDate>) (localDate, type, context)
-> new JsonPrimitive(localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))))
.registerTypeAdapter(LocalDate.class,
(JsonDeserializer<LocalDate>) (jsonElement, type, context)
-> LocalDate.parse(jsonElement.getAsString(), DateTimeFormatter.ofPattern("yyyy-MM-dd")))
.create();
}
...
}
That configuration allows me not only having configured my GsonHttpMessageConverter with the adapters for LocalDate but also having a singleton bean for this Gson configuration available for my application.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With