【问题标题】:Tapestry JPA Jackson DeserializationTapestry JPA Jackson 反序列化
【发布时间】:2018-11-30 15:57:50
【问题描述】:

我正在处理一个我最初没有创建的项目,其中数据存储在内存中。我目前正在将这些数据移动到数据库中。我正在使用hibernate和tapestry JPA来做到这一点。在项目中的某个时候,通过@JsonDeserialize 注释使用了Jackson 反序列化(实际上与UI 相关联,但我怀疑这是否相关)和反序列化器类(我们称之为DefinitionDeserializer)。 DefinitionDeserializer 然后创建数据库表 (D_DEFINITION) 的 POJO 表示的实例(我们称之为 Definition)。但是,D_DEFINITION 连接到另一个表 (D_TYPE)(因此还有另一个 POJO (PeriodType))。为了解决这个连接,我使用了一个挂毯服务(ConnectingService),我通常通过@Inject注解注入它。但是,当通过 new 关键字创建对象(我试图在其中注入服务,即 DefinitionDeserializer)时,我不能使用这种注入方法 - @987654333 似乎就是这种情况@注解。如果不通过@Inject 关键字注入,我也无法使用ConnectingService,因为那时我也无法在ConnectingService 中注入任何其他服务,我目前正在这样做。

我希望这个描述不会让您太困惑,我无法与您分享实际代码,而且我认为最小的示例不会更好,因为这是一个相当复杂的案例,并且不会t 是这么小的一段代码。但是,如果您需要,我可以尝试提供。

基本上,我需要一种方法告诉JsonDeserialize 采用挂毯服务,而不是创建DefinitionDeserializer 本身的实例。

编辑:类作为例子:

public DefinitionDeserializer extends StdDeserializer<Definition> {
    private static final long serialVersionUID = 1L;
    //TODO: The injection doesn't work yet
    @Inject
    private ConnectingService connectingService;

    public DefinitionDeserializer() {
        this(null);
    }

    public DefinitionDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public Definition deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        Definition pd = new Definition();
        JsonNode node = p.getCodec().readTree(p);
        if (node.has("type"))
            pd.setType(periodTypeDao.findByValue("PeriodType." + node.get("type").asText()));

        return pd;
    }

}

@Entity
@Table(name = Definition.TABLE_NAME)
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region =
        JpaEntityModelConstants.CACHE_REGION_ADMINISTRATION)
public class Definition {

    public static final String TABLE_NAME = "D_DEFINITION";
    private static final long serialVersionUID = 389511526676381027L;

    @Id
    @SequenceGenerator(name = JpaEntityModelConstants.SEQUENCE_NAME, sequenceName = JpaEntityModelConstants.SEQUENCE_NAME, initialValue = 1, allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = JpaEntityModelConstants.SEQUENCE_NAME)
    @Column(name = "ID")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({
            @JoinColumn(name = "FK_TYPE", referencedColumnName = "ID")}
    )
    private PeriodType type;


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public PeriodType getType() {
        return type;
    }

    public void setType(PeriodType dpmType) {
        this.type = dpmType;
    }

    //More columns
}

PeriodType 看起来与Definition 几乎相同。


//BaseService contains all the standard methods for tapestry JPA services
public interface ConnectingService extends BaseService<PeriodType> {

}

public class ConnectingServiceImpl extends BaseServiceImpl<PeriodType> implements ConnectingService {

    public ConnectingServiceImpl() {
        super (PeriodType.class);
    }
}

目前我正在这样使用它(这不起作用):

@JsonDeserialize(using = DefinitionDeserializer.class)
@JsonSerialize(using = DefinitionSerializer.class)
private Definition definition;

【问题讨论】:

  • 一个代码示例肯定会有所帮助。
  • @Christine 我编辑了我的问题

标签: java json hibernate jackson tapestry


【解决方案1】:

@JsonDeserialize 不会创建反序列化器的实例,它只是提示ObjectMapper 在反序列化时知道使用哪个类。

默认情况下,ObjectMapper 使用Class.newInstance() 来实例化反序列化器,但您可以指定自定义HandlerInstantiator (ObjectMapper#setHandlerInstantiator()),在其中您可以使用Tapestry 的ObjectLocator 来获取反序列化器的实例,即使用ObjectLocator#autobuild(),或使用ObjectLocator#getService() 如果您的反序列化器本身就是 Tapestry 服务。

更新:

public class MyHandlerInstantiator extends HandlerInstantiator
{
    private final ObjectLocator objectLocator;

    public MyHandlerInstantiator(ObjectLocator objectLocator)
    {
        this.objectLocator = objectLocator;
    }

    @Override
    public JsonDeserializer<?> deserializerInstance(
     DeserializationConfig config, Annotated annotated, Class<?> deserClass)
    {
        // If null returned here instance will be created via reflection
        // you can always use objectLocator, or use it conditionally
        // just for some classes
        return objectLocator.autobuild(deserClass);
    }

    // Other method overrides can return null
}

然后当您配置ObjectMapper 时,使用@Injected 的ObjectLocator 实例来创建自定义HandlerInstantiator 的实例,即:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setHandlerInstantiator(new MyHandlerInstantiator(objectLocator));
return objectMapper;

【讨论】:

  • 这看起来很有希望 - 您能否提供一个如何指定 HandlerInstantiator 的最小示例?我目前不知道在哪里放ObjectLocator#autobuild()
  • 谢谢。但是,当我尝试通过@Inject 使用ObjectLocator 时,我遇到了异常:No service implements the interface org.apache.tapestry5.ioc.ObjectLocator.
  • 如果您尝试将@Inject 直接添加到页面/组件类中,我已经注意到了这种行为,但是服务中的注入或 Tapestry 模块中的构建器/贡献方法应该可以正常工作;您还应该能够将包含ObjectLocator@Inject 服务毫无问题地添加到页面/组件类
  • 但是我该怎么做呢?因为目前我在页面内使用ObjectMapper
  • 创建这样的挂毯服务: public class ObjectLocatorProvider { @Inject ObjectLocator objectLocator; public ObjectLocator getObjectLocator() { return objectLocator; } } 并将其注入您的页面
猜你喜欢
  • 1970-01-01
  • 2015-10-28
  • 2019-09-17
  • 2021-01-19
  • 1970-01-01
  • 2013-01-01
  • 2016-12-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多