将无状态会话bean注入自定义JsonDeserializer失败

时间:2016-08-23 21:45:11

标签: java json jackson cdi

我正在构建一个使用JPA(EclipseLink)提供JAX-RS REST服务的应用程序。当通过JSON公开用户实体时,我在某些字段(例如密码字段)上使用@XmlTransient注释来将它们隐藏在JSON表示中。发送创建或更新(POST / PUT)操作时,我想再次填充缺少的字段,以便JPA正确执行操作。

我目前的做法是,我有一个自定义JsonDeserializer,用于反序列化用户并添加缺少的字段。为此,我想注入(使用@Inject)一个UserFacadeREST bean处理JPA的东西。但是,此注入失败,bean实例为null(当然会导致NullPointerException)。

我的UserFacadeREST bean的注释如下:

@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 {
    // ...
}

我在我的WEB-INF文件夹中包含了一个bean.xml文件,bean-discovery-mode设置为all。我错过了什么?

2 个答案:

答案 0 :(得分:3)

Jon Peterson向我指出了正确的方向。我终于选择以某种方式实施“hackish”解决方案。请注意,这里基本上有两个选项(如果你知道另一个,请告诉我!)。简短版本:

  1. Hackish解决方案(我选择的解决方案):使用javax.enterprise.inject.spi.CDI.current().select(UserFacadeRest.class).get()以编程方式注入bean,如Jon提到的问题的accepted answer
  2. 所述
  3. 更好(干净)的解决方案(但也更精细):重新设计逻辑以在反序列化后填充缺少的字段,如Jon所建议。
  4. 因此,对于我的问题,解决方案如下所示:

    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的{​​{1}}方法中,我将构建一个只保存userID的用户。在每个请求方法中,我都必须检查所有用户,并通过调用JsonDeserializer由实际用户替换它们。这意味着更多的业务逻辑工作,因为您必须记住,每当您需要在请求方法中处理EntityManager.find(User.class, user.getUserID())时,首先必须执行查询以获取“完整”{{1}对象。在第一个解决方案中,此查询对业务逻辑是隐藏的,并且已经在User

    中发生
    User

答案 1 :(得分:1)

我对CDI并不是很熟悉,但是一些快速的Google会让我相信bean-discovery-mode应该是allannotatednonetrue不是有效值。 Reference

如果没有解决问题,可能是Spring会遇到的问题:你必须将UserDeserializer声明为bean,以便应用依赖注入。

编辑:刚发现这个other question基本上与您遇到的问题相同。

最终,您可能需要重新设计逻辑以在反序列化后调用userFacade