JSON using GSON-Library: Error Expected BEGIN_OBJECT but was STRING

gson, java, json, parsing

Solution

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();

Problem

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

Original source