Tapestry JPA 杰克逊反序列化
Tapestry JPA Jackson Deserialization
我正在处理一个最初不是我创建的项目,其中的数据存储在内存中。我正在将这些数据移动到数据库中。我正在使用休眠和挂毯 JPA 执行此操作。在项目中的某个时候,使用了 Jackson 反序列化(实际上与 UI 有关,但我怀疑这是否相关),通过 @JsonDeserialize
注释,使用反序列化器 class(我们称它为DefinitionDeserializer
)。 DefinitionDeserializer
然后创建数据库 table (D_DEFINITION
) 的 POJO 表示实例(我们称之为 Definition
)。但是,D_DEFINITION
与另一个 table (D_TYPE
) 有连接(因此还有另一个 POJO (PeriodType
))。为解决此连接,我使用了挂毯服务 (ConnectingService
),我通常通过 @Inject
注释注入该服务。但是,当对象(我试图在其中注入服务,即 DefinitionDeserializer
)是通过 new
关键字创建时,我无法使用这种注入方法 - 这似乎是这种情况对于 @JsonDeserialize
注释。如果不通过 @Inject
关键字注入它,我也不能使用 ConnectingService
,因为那时我也无法在 ConnectingService
中注入任何其他服务,而我目前正在这样做。
我希望这个描述不会让您感到困惑,我无法与您分享实际的代码,而且我认为一个最小的示例不会更好,因为它是一个相当复杂的案例并且不会是这么小的一段代码。不过如果你需要的话,我可以尽量提供。
基本上我需要的是告诉 JsonDeserialize
使用挂毯服务而不是创建 DefinitionDeserializer
本身的实例的方法。
编辑: classes 作为示例:
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;
@JsonDeserialize
不会创建反序列化器的实例,它只是提示 ObjectMapper
知道在反序列化时使用哪个 class。
默认情况下,ObjectMapper 使用 Class.newInstance()
来实例化反序列化器,但您可以指定自定义 HandlerInstantiator
(ObjectMapper#setHandlerInstantiator()
),您可以在其中使用 Tapestry 的 ObjectLocator
来获取实例反序列化器,即使用 ObjectLocator#autobuild()
,或者如果您的反序列化器本身就是 Tapestry 服务,则使用 ObjectLocator#getService()
。
更新:
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
时使用 @Inject
ed 的 ObjectLocator
实例来创建自定义 HandlerInstantiator
的实例,即:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setHandlerInstantiator(new MyHandlerInstantiator(objectLocator));
return objectMapper;
我正在处理一个最初不是我创建的项目,其中的数据存储在内存中。我正在将这些数据移动到数据库中。我正在使用休眠和挂毯 JPA 执行此操作。在项目中的某个时候,使用了 Jackson 反序列化(实际上与 UI 有关,但我怀疑这是否相关),通过 @JsonDeserialize
注释,使用反序列化器 class(我们称它为DefinitionDeserializer
)。 DefinitionDeserializer
然后创建数据库 table (D_DEFINITION
) 的 POJO 表示实例(我们称之为 Definition
)。但是,D_DEFINITION
与另一个 table (D_TYPE
) 有连接(因此还有另一个 POJO (PeriodType
))。为解决此连接,我使用了挂毯服务 (ConnectingService
),我通常通过 @Inject
注释注入该服务。但是,当对象(我试图在其中注入服务,即 DefinitionDeserializer
)是通过 new
关键字创建时,我无法使用这种注入方法 - 这似乎是这种情况对于 @JsonDeserialize
注释。如果不通过 @Inject
关键字注入它,我也不能使用 ConnectingService
,因为那时我也无法在 ConnectingService
中注入任何其他服务,而我目前正在这样做。
我希望这个描述不会让您感到困惑,我无法与您分享实际的代码,而且我认为一个最小的示例不会更好,因为它是一个相当复杂的案例并且不会是这么小的一段代码。不过如果你需要的话,我可以尽量提供。
基本上我需要的是告诉 JsonDeserialize
使用挂毯服务而不是创建 DefinitionDeserializer
本身的实例的方法。
编辑: classes 作为示例:
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;
@JsonDeserialize
不会创建反序列化器的实例,它只是提示 ObjectMapper
知道在反序列化时使用哪个 class。
默认情况下,ObjectMapper 使用 Class.newInstance()
来实例化反序列化器,但您可以指定自定义 HandlerInstantiator
(ObjectMapper#setHandlerInstantiator()
),您可以在其中使用 Tapestry 的 ObjectLocator
来获取实例反序列化器,即使用 ObjectLocator#autobuild()
,或者如果您的反序列化器本身就是 Tapestry 服务,则使用 ObjectLocator#getService()
。
更新:
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
时使用 @Inject
ed 的 ObjectLocator
实例来创建自定义 HandlerInstantiator
的实例,即:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setHandlerInstantiator(new MyHandlerInstantiator(objectLocator));
return objectMapper;