【问题标题】:Jersey Rest - JsonMappingException: No suitable constructor found for type [simple type, class ]Jersey Rest - JsonMappingException:没有为类型 [简单类型,类] 找到合适的构造函数
【发布时间】:2015-04-19 08:42:35
【问题描述】:

我使用 jax-rs 和 jersey 创建了一个 REST API。我想从我的 REST API 中的外部库返回 JSON 格式的对象。然而,该对象没有默认构造函数,这会导致以下异常:

Caused by: org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class ....EncryptionToken]: can not instantiate from JSON object (need to add/enable type information?) 

通过 REST API 返回此对象的最佳方式是什么?

这是我的 REST API 实现:

@GET
@Produces(MediaType.APPLICATION_JSON)
public javax.ws.rs.core.Response get( //
            @QueryParam("etkIdentifierType") String etkIdentifierType, //
            @QueryParam("etkIdentifierValue") String etkIdentifierValue, //
            @QueryParam("applicationId") String applicationId) {
    LOG.info("GET Request: Lookup encryption token for etkIdentifierType [" + etkIdentifierType + "], etkIdentifierValue [" + etkIdentifierValue + "] and applicationId [" + applicationId + "]");
    final EncryptionToken token = etkService.getETK(etkIdentifierType, etkIdentifierValue, applicationId);
    return Response.ok(token).build();
}

Encryption 类来自我无法修改的外部库。我首先尝试用相同的变量构造一个自己的对象并返回它,但并不是所有的 getter 方法都是公共的。

这是 EncryptionToken 类:

package ...;

public class EncryptionToken {
    private java.security.cert.X509Certificate encrCert;
    private byte[] encoded;
    private java.security.cert.X509Certificate authCert;
    private java.security.cert.X509Certificate etkRaCert;
    private java.util.List<java.security.cert.X509Certificate> caCertChain;

    EncryptionToken(byte[] encoded, java.security.cert.X509Certificate encrCert, java.security.cert.X509Certificate authCert, java.util.List<java.security.cert.X509Certificate> caCertChain, java.security.cert.X509Certificate etkRaCert) { /* compiled code */ }

    public final byte[] getEncoded() { /* compiled code */ }

    public final byte[] getBase64Encoded() { /* compiled code */ }

    public final java.security.cert.X509Certificate getCertificate() { /* compiled code */ }

    public final java.security.cert.X509Certificate getAuthenticationCertificate() { /* compiled code */ }

    java.util.List<java.security.cert.X509Certificate> getCaCertChain() { /* compiled code */ }

    java.security.cert.X509Certificate getEtkRaCert() { /* compiled code */   }
}

编辑:我认为我需要一个反序列化器。代码在以下行失败:

final EncryptionToken encryptionToken = response.getEntity(EncryptionToken.class);

但由于我无法实例化 EncryptionToken(没有默认构造函数,并且可用的构造函数是公开的)我不知道如何解决这个问题......

【问题讨论】:

  • 向 EncryptionToken 添加一个默认(非参数)构造函数。也许杰克逊创建一个空实例,然后通过 getters/setters 放置属性
  • @bigdestroyer 这是我的第一个想法,但不幸的是我无法访问 EncryptionToken 类,因为它位于我无法修改内容的外部 jar 中。我的另一个想法是扩展这个类,但构造函数是包保护的。第三种解决方案是创建一个具有相同变量的新类并传递它,但由于并非所有 getter 都是公共的,而且我使用的其他方法使用 EncryptionToken 对象,所以我无法在对象之间编写一个像样的映射器......跨度>

标签: java json api rest jersey


【解决方案1】:

您可以实现自定义 JsonSerializer 对象并将其注册到 Jackson 上下文中。

public class EncryptionTokenSerializer extends JsonSerializer<EncryptionToken> {
    @Override
    public void serialize(EncryptionToken value, JsonGenerator jgen, SerializerProvider provider) 
      throws IOException {
        jgen.writeStartObject();
        jgen.writeBinaryField("encoded", value.getEncoded());
        jgen.writeBinaryField("base64Encoded", value.getBase64Encoded());
        jgen.writeEndObject();
    }
}

如果您想知道如何在上下文中注册序列化程序,请查看this answer

【讨论】:

  • 感谢您的示例。这是非常有前途的。但是,您如何将此自定义序列化程序注册到您的杰克逊上下文中?我会用 @JsonSerialize(using = EncryptionTokenSerializer.class) 注释类,但由于我无权访问 EncryptionToken 类,所以我不能这样做......
  • 我设法通过了 EncryptionTokenSerializer(在调试模式下),但不幸的是我仍然收到 EncryptionToken 类缺少默认构造函数的投诉...com.sun.jersey.api.client.ClientHandlerException: org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class be.fgov.ehealth.etee.crypto.encrypt.EncryptionToken]: can not instantiate from JSON object (need to add/enable type information?) at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@77da01; line: 1, column: 2]
【解决方案2】:

嘿,我在我的机器上尝试了你的代码。我执行它没有任何问题。 它给了我正确的结果。 您能否提供方法“etkService.getETK()”的实现以及“etkService”的声明和定义。因此可能会出现一些问题。

最终的 EncryptionToken token = etkService.getETK(etkIdentifierType, etkIdentifierValue, applicationId);

而且不需要为你的 POJO 提供反序列化器

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 1970-01-01
    • 2012-06-24
    • 2015-06-26
    • 2019-03-28
    • 1970-01-01
    相关资源
    最近更新 更多