如何防止调用close方法?

时间:2015-09-23 07:39:46

标签: jpa ejb jax-rs

我打算为那些非容器管理的客户端(如JRX-RS资源)编写业务方法。

@Stateless
public class PersistenceService {

    public <R> R apply(final Function<EntityManager, R> function) {
        return function.apply(entityManager);
    }

    @PersistenceContext
    private transient EntityManager entityManager;
}

这样JAX-RS根资源类就像这样使用它。

@RequestScoped
@Path("/entities")
public class MyEntites {

    @GET
    @Path("/{id: \\d+}")
    public Response read(final long id) {

        return Response.ok(service.apply(m -> {
            m.find(MyEntity.class, id);
        })).build();
    }

    @Inject
    private transient PersistenceService service;
}

问题是如何阻止客户端在指定的实体管理器上调用close()

service.apply(m -> {
    m.close();
    return null;
});

2 个答案:

答案 0 :(得分:1)

您可以围绕原始实体管理器创建一个包装器,以确保永远不会调用close()

public class NoCloseEntityManager implements EntityManager {
  private EntityManager wrapped;
  public NoCloseEntityManager(EntityManager wrapped) {
    this.wrapped = wrapped;
  }

  public void close() { 
    throw new UnsupportedOperationException("Don't call close()");
  }

  // all other methods from the interface call the wrapped manager:
  public void persist(Object entity) {
    wrapped.persist(entity);
  }
  ...
}

您可以在服务中使用:

@Stateless
public class PersistenceService {

    @PersistenceContext
    private transient EntityManager entityManager;

    public <R> R apply(final Function<EntityManager, R> function) {
        return function.apply(new NoCloseEntityManager(entityManager));
    }

}

但是我不知道结果的努力是否更糟,因为entityManager.close()并非经常被调用 - 如果有人打电话给他,他就不会错误地使用它...... < / p>

答案 1 :(得分:0)

我为任何人提供了另一种可能的解决方案。

@Stateless
public class PersistenceService {

    private static final Method CLOSE;

    static {
        try {
            CLOSE = EntityManager.class.getMethod("close");
        } catch (final NoSuchMethodException nsme) {
            throw new InstantiationError(nsme.getMessage());
        }
    }

    @PostConstruct
    private void constructed() {
        entityManager = (EntityManager) Proxy.newProxyInstance(
            entityManager_.getClass().getClassLoader(),
            new Class<?>[]{EntityManager.class},
            (proxy, method, args) -> {
                if (CLOSE.equals(method)) {
                    throw new RuntimeException("i'll find you.");
                }
                return method.invoke(entityManager_, args);
            });
    }

    @PreDestroy
    private void destroying() {
        entityManager = null;
    }

    @PersistenceContext
    private transient EntityManager entityManager_;

    private transient EntityManager entityManager;
}

现在我可以添加所需的方法。

public <R> R apply(final Function<EntityManager, R> function) {
    return function.apply(entityManager);
}

public <U, R> R apply(final BiFunction<EntityManager, U, R> function,
                      final U u) {
    return function.apply(entityManager, u);
}

public int applyAsInt(final ToIntFunction<EntityManager> function) {
    return function.applyAsInt(entityManager);
}

public <U> int applyAsInt(final ToIntBiFunction<EntityManager, U> function,
                          final U u) {
    return function.applyAsInt(entityManager, u);
}

public long applyAsLong(final ToLongFunction<EntityManager> function) {
    return function.applyAsLong(entityManager);
}

public <U> long applyAsLong(
    final ToLongBiFunction<EntityManager, U> function, final U u) {
    return function.applyAsLong(entityManager, u);
}

public double applyAsDouble(
    final ToDoubleFunction<EntityManager> function) {
    return function.applyAsDouble(entityManager);
}

public <U> double applyAsDouble(
    final ToDoubleBiFunction<EntityManager, U> function, final U u) {
    return function.applyAsDouble(entityManager, u);
}