2016-08-23 4 views
1

Я создаю приложение, предоставляющее службу REST JAX-RS, используя JPA (EclipseLink). При экспонировании объектов пользователя над JSON я использую аннотацию @XmlTransient в некоторых полях (например, поле пароля), чтобы скрыть их от представления JSON. При отправке операции создания или обновления (POST/PUT) я хотел бы снова заполнить недостающие поля, чтобы JPA корректно выполнил операцию.Включение сеанса сеанса без состояния в пользовательский JsonDeserializer завершается

Мой текущий подход заключается в том, что у меня есть пользовательский JsonDeserializer, который используется для десериализации пользователя и добавления недостающих полей. Для этого я хотел бы ввести (используя @Inject) фасоль UserFacadeREST, который обрабатывает JPA-материал. Однако эта инъекция терпит неудачу, а экземпляр компонента - null (который, конечно же, вызывает NullPointerException).

Мой UserFacadeREST боб annoted следующим образом:

@Stateless 
@LocalBean 
@Path(UserFacadeREST.PATH) 
public class UserFacadeREST extends AbstractFacade<User> { 
    //... 
} 

Мои UserDeserilizer (пользовательские JsonDeserializer):

public class UserDeserializer extends JsonDeserializer<User> { 

    @Inject 
    private UserFacadeREST userFacade; 

    @Override 
    public User deserialize(JsonParser parser, DeserializationContext context) throws IOException, 
     JsonProcessingException { 
    JsonNode node = parser.getCodec().readTree(parser); 
    int userId = (Integer) ((IntNode) node.get("userID")).numberValue(); 
    System.out.println(userId); 
    User user = userFacade.find(userId); // This line produces the NullPointerException 
    return user; 
    } 

} 

который я тогда использовать на пользователя объекта с @JsonDeserialize:

@Entity 
@Table(name = "User") 
@XmlRootElement 
@JsonDeserialize(using = UserDeserializer.class) 
public class User implements Serializable { 
    // ... 
} 

Я включил файл bean.xml в свой W EB-INF с bean-discovery-mode установлена ​​в all. Что мне не хватает?

+0

Вы можете только @ Включить объекты, управляемые контейнером CDI. Поскольку 'UserDeserializer' не объявляется управляемым компонентом, инъекция зависимости не должна происходить, поскольку контейнер не будет предоставлять вам эту услугу. – scottb

+0

Спасибо. Итак, как я объявляю свой UserDeserializer управляемым компонентом? Я пробовал с помощью '@ ApplicationScoped' и' @ Singleton', но никто не работал ... – Severin

ответ

3

Джон Петерсон указал мне в правильном направлении. Наконец, я решил реализовать «хакерское» решение. Обратите внимание, что здесь есть в основном 2 варианта (если вы знаете другой, сообщите мне об этом!). Короткая версия:

  1. хак решение (решение, которое я выбрал): впрыснуть боб программно с помощью javax.enterprise.inject.spi.CDI.current().select(UserFacadeRest.class).get(), как описано в accepted answer вопросе, упомянутый Джоном или
  2. Лучше (чистый) раствор (но также более подробно): переконфигурируйте логику, чтобы заполнить недостающие поля после десериализация, предложенная Джоном.

Так мой вопрос, решение выглядит следующим образом:

1.

import javax.enterprise.inject.spi.CDI; 

public class UserDeserializer extends JsonDeserializer<User> { 

    private final UserFacadeREST userFacade = 
     CDI.current().select(UserFacadeREST.class).get(); 

    // Rest as before 
} 

2. В этом случае в deserialize методе моего JsonDeserializer я бы построить пользователь, который просто держит идентификатор_пользователь. В каждом методе запроса мне пришлось бы изучить всех пользователей и заменить их фактическим пользователем, вызвав EntityManager.find(User.class, user.getUserID()). Это означает больше усилий в бизнес-логике, поскольку вам нужно помнить, что каждый раз, когда вам нужно работать с User в методе запроса, вам сначала нужно выполнить запрос, чтобы получить «полный» объект User. В первом решении этот запрос скрыт от бизнес-логики и уже происходит в JsonDeserializer.

public class UserDeserializer extends JsonDeserializer<User> { 

    @Override 
    public User deserialize(JsonParser parser, DeserializationContext context) throws IOException, 
     JsonProcessingException { 
    JsonNode node = parser.getCodec().readTree(parser); 
    int userId = (Integer) ((IntNode) node.get("userID")).numberValue(); 
    return new User(userId); // Placeholder User object containing only the user ID, needs to be replaced in business logic 
    } 

} 
1

Я не супер знакомы с КДИ, но некоторые быстро Google'ing приводит меня к мысли, что bean-discovery-mode должен быть либо all, annotated или none (true не является допустимым значением). Reference

Если это не исправить, это может быть та же проблема, что и Spring: вы должны объявить свой UserDeserializer в качестве компонента для инъекции зависимостей, которая будет применяться.

EDIT: Только что нашел это other question, что в основном та же проблема, что и у вас.

В конечном счете вам, вероятно, нужно просто перепроектировать логику, чтобы позвонить по телефону userFacade после десериализации.

+0

Жаль, вы абсолютно правы. Я фактически использовал «все», просто смутил его при написании вопроса. Я только что проверил, и проект даже не компилируется при использовании 'true'. Итак, как я объявляю свой 'UserDeserializer' в качестве компонента? Конечно, с какой-то аннотацией, но какой? – Severin

+0

После того, как я дал это второе, я действительно не думаю, что это можно сделать вообще. Экземпляры 'UserDeserializer' будут созданы Jackson, а не CDI. Это означает, что аннотации CDI (ex '@ Inject') не будут обрабатываться. Я только что нашел другой вопрос, который я собираюсь внести в отредактированный ответ: –

+0

Спасибо, Джон, ты указал мне в правильном направлении. Внедрение экземпляра UserFacadeREST программно работает для меня, поэтому я выбрал этот подход, так как он требует меньше усилий, и у нас есть «пополнение» недостающих полей в одном месте и абстрагируется от бизнес-логики. Но я понимаю, что это не лучший способ. Я попытался подчеркнуть это в своем ответе и упомянуть оба подхода, поэтому я буду отмечать мой как принятый, на всякий случай, если кто-либо предпочитает придерживаться инъекции. – Severin

Смежные вопросы