Гобелен JPA Джексон Десериализация - PullRequest
0 голосов
/ 30 ноября 2018

Я работаю над проектом, который изначально не создавал, в котором данные хранились в памяти.Я сейчас перемещаю эти данные в базу данных.Я делаю это с использованием спящего и гобеленового JPA.В какой-то момент в проекте используется десериализация Jackson (на самом деле в связи с пользовательским интерфейсом, но я сомневаюсь, что это актуально) через аннотацию @JsonDeserialize с классом десериализатора (назовем его DefinitionDeserializer).DefinitionDeserializer затем создает экземпляр представления POJO (назовем его Definition) таблицы базы данных (D_DEFINITION).Однако D_DEFINITION имеет соединение с другой таблицей (D_TYPE) (и, следовательно, с другим POJO (PeriodType)).Чтобы разрешить это соединение, я использую сервис гобеленов (ConnectingService), который я обычно добавляю через аннотацию @Inject.Однако я не могу использовать этот метод внедрения, когда объект (в котором я пытаюсь внедрить службу, т.е. DefinitionDeserializer) был создан с помощью ключевого слова new - что, похоже, имеет место для @JsonDeserialize аннотация.Я также не могу использовать ConnectingService, не вводя его через ключевое слово @Inject, потому что тогда я не смог бы внедрить и другие сервисы в ConnectingService, что я сейчас и делаю.

I 'Надеюсь, это описание не слишком вас смутило, я не могу поделиться с вами настоящим кодом и не думаю, что минимальный пример был бы намного лучше, так как это довольно сложный случай и не будет таким маленькимкусок кода.Однако, если он вам нужен, я могу попытаться его предоставить.

По сути, мне нужен способ заставить 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;

1 Ответ

0 голосов
/ 01 декабря 2018

@JsonDeserialize не создает экземпляров десериализаторов, это просто подсказка для ObjectMapper, чтобы знать, какой класс использовать при десериализации.

По умолчанию ObjectMapper использует Class.newInstance() для создания экземпляров десериализаторов, но выможно указать пользовательский HandlerInstantiator (ObjectMapper#setHandlerInstantiator()), в котором вы можете использовать Tapestry's 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 используйте @Inject ed экземпляр ObjectLocator, чтобы создать экземпляр пользовательского HandlerInstantiator, то есть:

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