Skip to content

Instantly share code, notes, and snippets.

@pmuir
Created August 28, 2012 15:51
Show Gist options
  • Save pmuir/3499355 to your computer and use it in GitHub Desktop.
Save pmuir/3499355 to your computer and use it in GitHub Desktop.
public class NonContextualInjector<T> {
// Store the injection target. The CDI spec doesn't require an implementation to cache it, so we do
private final InjectionTarget<T> injectionTarget;
// Store a reference to the CDI BeanManager
private final BeanManager beanManager;
/**
* Create an injector for the given class
*/
public NonContextual(BeanManager manager, Class<T> clazz) {
this.beanManager = manager;
// Generate an "Annotated Type"
AnnotatedType<T> type = manager.createAnnotatedType(clazz);
// Generate the InjectionTarget
this.injectionTarget = manager.createInjectionTarget(type);
}
/**
* Create an injector for the given class
*/
public NonContextual(BeanManager manager, AnnotatedType<T> type) {
this.beanManager = manager;
// Generate the InjectionTarget
this.injectionTarget = manager.createInjectionTarget(type);
}
/**
* Create an injector for the given class
*/
public NonContextual(Class<T> clazz) {
this.beanManager = CDI.current().getBeanManager();
// Generate an "Annotated Type"
AnnotatedType<T> type = manager.createAnnotatedType(clazz);
// Generate the InjectionTarget
this.injectionTarget = manager.createInjectionTarget(type);
}
/**
* Create an injector for the given class
*/
public NonContextual(AnnotatedType<T> type) {
this.beanManager = CDI.current().getBeanManager();
// Generate the InjectionTarget
this.injectionTarget = manager.createInjectionTarget(type);
}
public Instance<T> newInstance() {
return new Instance<T>(beanManager, injectionTarget);
}
/**
* Represents a non-contextual instance
*/
public static class Instance<T>
{
private final CreationalContext<T> ctx;
private final InjectionTarget<T> injectionTarget;
private T instance;
private boolean disposed = false;
private Instance(BeanManager beanManager, InjectionTarget<T> injectionTarget) {
this.injectionTarget = injectionTarget;
this.ctx = beanManager.createCreationalContext(null);
}
/**
* Get the instance
*/
public T get() {
if (disposed) {
throw new IllegalStateException("Trying to call get() on an already disposed instance");
}
if (this.instance == null) {
produce();
inject();
postConstruct();
}
return instance;
}
public void destroy() {
if (this.instance == null) {
throw new IllegalStateException("Trying to call destroy() before the instance was created was called");
}
if (disposed) {
throw new IllegalStateException("Trying to call destroy() on already disposed instance");
}
preDestroy();
dispose();
}
/**
* Create the instance
*/
public Instance<T> produce() {
if (this.instance != null) {
throw new IllegalStateException("Trying to call produce() on already constructed instance");
}
if (disposed) {
throw new IllegalStateException("Trying to call produce() on an already disposed instance");
}
this.instance = injectionTarget.produce(ctx);
return this;
}
/**
* Inject the instance
*/
public Instance<T> inject() {
if (this.instance == null) {
throw new IllegalStateException("Trying to call inject() before produce() was called");
}
if (disposed) {
throw new IllegalStateException("Trying to call inject() on already disposed instance");
}
injectionTarget.inject(instance, ctx);
return this;
}
/**
* Call the @PostConstruct callback
*/
public Instance<T> postConstruct() {
if (this.instance == null) {
throw new IllegalStateException("Trying to call postConstruct() before produce() was called");
}
if (disposed) {
throw new IllegalStateException("Trying to call preDestroy() on already disposed instance");
}
injectionTarget.postConstruct(instance);
return this;
}
/**
* Call the @PreDestroy callback
*/
public Instance<T> preDestroy() {
if (this.instance == null) {
throw new IllegalStateException("Trying to call preDestroy() before produce() was called");
}
if (disposed) {
throw new IllegalStateException("Trying to call preDestroy() on already disposed instance");
}
injectionTarget.preDestroy(instance);
return this;
}
/**
* Dispose of the instance, doing any necessary cleanup
*/
public Instance<T> dispose() {
if (this.instance == null) {
throw new IllegalStateException("Trying to call dispose() before produce() was called");
}
if (disposed) {
throw new IllegalStateException("Trying to call dispose() on already disposed instance");
}
injectionTarget.dispose(instance);
ctx.release();
return this;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment