如何防止调用 close 方法?
How can I prevent from a close method being invoked?
我打算为那些非容器管理的客户端(例如 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 根资源 class 像这样使用它。
@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;
});
您可以围绕原始实体管理器创建一个包装器,以确保永远不会调用 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()
不经常被调用 - 如果有人调用它,他不会错误地使用它...
我正在发布另一个可能的解决方案以供大家参考。
@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);
}
我打算为那些非容器管理的客户端(例如 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 根资源 class 像这样使用它。
@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;
});
您可以围绕原始实体管理器创建一个包装器,以确保永远不会调用 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()
不经常被调用 - 如果有人调用它,他不会错误地使用它...
我正在发布另一个可能的解决方案以供大家参考。
@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);
}