8

我正在尝试使用 gson 将 json 字符串解析回 Java 对象。但我不断收到上述错误:

Expected BEGIN_OBJECT but was STRING.

我看到这个错误有一些 SO 问题,但似乎没有一个适用于我的情况。

我的 Java 代码如下:

Gson gson = new Gson();
Payment p = gson.fromJson(paymentJson, Payment.class);

其中paymentJson 是支付对象的JSON 字符串,我通过http 帖子获取。

我用来测试它的 Json-String 如下:

{
"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

}

我用 JsonLint 检查了 JSON 的有效性,它是有效的 json。

我知道通过 http 向我发送 json 数据的另一方也使用 GSON 和同一个类“付款”,但我不能/不允许在那里更改代码。

付款类如下所示:

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;
  }
}

编辑:这是堆栈跟踪:

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)

有谁知道为什么我会收到该错误消息?

提前致谢

4

2 回答 2

31

GSON 无法解析 creationDate 字段的值,因为它不知道如何处理 Joda-Time DateTime 对象。

尝试使用 GsonBuilder 的 registerTypeAdapter 方法为此类注册类型适配器。

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();
于 2013-04-15T09:44:07.160 回答
1

我实现了一种稍微不同的方法,因为在我的情况下,我的 Spring Boot 项目中 java.time.LocalDate 的序列化和反序列化属性都存在问题:

@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();
    }
    ...
}

该配置不仅允许我为我的 GsonHttpMessageConverter 配置了 LocalDate 的适配器,而且还为我的应用程序提供了这个 Gson 配置的单例 bean。

于 2020-06-08T00:25:35.143 回答