Skip to content

Commit

Permalink
GenericProduct support
Browse files Browse the repository at this point in the history
  • Loading branch information
pmuir committed Jul 26, 2010
1 parent 86299d9 commit 08b45af
Show file tree
Hide file tree
Showing 19 changed files with 851 additions and 26 deletions.
Expand Up @@ -39,6 +39,10 @@
* injections can only occur in other generic beans which share the same config
* annotation.
*
* <ul>
* <li>Only works on injected fields</li>
* </ul>
*
*
* @author stuart
* @author Pete Muir
Expand Down
Expand Up @@ -15,8 +15,8 @@
* limitations under the License.
*/
package org.jboss.weld.extensions.bean.generic;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -56,6 +56,7 @@
import org.jboss.weld.extensions.bean.BeanBuilder;
import org.jboss.weld.extensions.bean.BeanLifecycle;
import org.jboss.weld.extensions.util.Arrays2;
import org.jboss.weld.extensions.util.Reflections;
import org.jboss.weld.extensions.util.Synthetic;

/**
Expand Down Expand Up @@ -87,9 +88,14 @@ class GenericBeanExtension implements Extension
// A map of a generic configuration types to generic configurations
// Used to track the generic configuration producers found
private final Map<Class<? extends Annotation>, Map<Annotation, AnnotatedMember<?>>> genericProducers;

private final Map<Annotation, Producer<?>> originalProducers;

// The Synthetic qualifier provider
// The Synthetic qualifier provider for generic beans, and configuration injection
private final Synthetic.Provider syntheticProvider;

// The Synthetic qualifier provider for generic product beans
private final Synthetic.Provider productSyntheticProvider;

GenericBeanExtension()
{
Expand All @@ -98,7 +104,9 @@ class GenericBeanExtension implements Extension
this.genericBeanProducerFields = new HashMap<AnnotatedType<?>, Map<AnnotatedField<?>, Bean<?>>>();
this.genericInjectionTargets = new HashMap<Class<? extends Annotation>, Map<AnnotatedType<?>, InjectionTarget<?>>>();
this.genericProducers = new HashMap<Class<? extends Annotation>, Map<Annotation, AnnotatedMember<?>>>();
this.originalProducers = new HashMap<Annotation, Producer<?>>();
this.syntheticProvider = new Synthetic.Provider("org.jboss.weld.extensions.bean.generic");
this.productSyntheticProvider = new Synthetic.Provider("org.jboss.weld.extensions.bean.generic.product");
}

<X> void replaceInjectOnGenericBeans(@Observes ProcessAnnotatedType<X> event)
Expand All @@ -113,15 +121,26 @@ <X> void replaceInjectOnGenericBeans(@Observes ProcessAnnotatedType<X> event)

public void redefine(RedefinitionContext<Inject> ctx)
{
if (ctx.getRawType().equals(genericConfigurationType))
{
// This is a Generic configuration injection point
ctx.getAnnotationBuilder().remove(Inject.class).add(InjectGeneric.INSTANCE);
}
else if (ctx.getAnnotatedElement().isAnnotationPresent(GenericBean.class))
if (ctx.getAnnotatedElement() instanceof Field)
{
// This is a Generic bean injection point
ctx.getAnnotationBuilder().remove(Inject.class).add(InjectGeneric.INSTANCE);
if (ctx.getRawType().equals(genericConfigurationType))
{
// This is a Generic configuration injection point
ctx.getAnnotationBuilder().remove(Inject.class).add(InjectGeneric.INSTANCE);
}
else if (ctx.getAnnotatedElement().isAnnotationPresent(GenericBean.class))
{
// This is a Generic bean injection point
ctx.getAnnotationBuilder().remove(Inject.class).add(InjectGeneric.INSTANCE);
}
else if (ctx.getAnnotatedElement().isAnnotationPresent(GenericProduct.class))
{
/*
* This is an injection point where @GenericProduct has
* been used, so we have to take control of injection
*/
ctx.getAnnotationBuilder().remove(Inject.class).add(InjectGeneric.INSTANCE);
}
}
}

Expand Down Expand Up @@ -211,12 +230,15 @@ <T, X> void registerGenericProducer(@Observes ProcessProducer<T, X> event, BeanM
Annotation genericConfiguration = getGenericConfiguration(event.getAnnotatedMember());
if (genericConfiguration != null)
{
Producer<X> originalProducer = event.getProducer();

// Replace the producer, so that our generic bean is produced
Producer<X> genericProducer = new GenericBeanProducer<X>(event.getProducer(), event.getAnnotatedMember().getBaseType(), genericConfiguration, syntheticProvider, beanManager);
Producer<X> genericProducer = new GenericBeanProducer<X>(originalProducer, event.getAnnotatedMember().getBaseType(), genericConfiguration, syntheticProvider, beanManager);
event.setProducer(genericProducer);

// Register the producer for use later
addGenericProducer(genericConfiguration, event.getAnnotatedMember());
addOriginalProducer(genericConfiguration, originalProducer);
}
}

Expand All @@ -233,6 +255,9 @@ void createGenericBeans(@Observes AfterBeanDiscovery event, BeanManager beanMana
{
// Add a generic configuration bean for each generic configuration producer (allows us to inject the generic configuration annotation back into the generic bean)
event.addBean(createGenericConfigurationBean(beanManager, genericConfiguration));

// Register the GenericProduct bean
event.addBean(createGenericProductBean(beanManager, genericConfiguration));
}
// For each generic bean that uses this genericConfigurationType, register a generic bean for this generic configuration
for (Entry<AnnotatedType<?>, Bean<?>> type : genericBeans.get(genericConfigurationType.getKey()).entrySet())
Expand All @@ -241,6 +266,7 @@ void createGenericBeans(@Observes AfterBeanDiscovery event, BeanManager beanMana
{
Bean<?> originalBean = type.getValue();
event.addBean(createGenericBean(originalBean, genericConfiguration.getKey(), (AnnotatedType) type.getKey(), beanManager));

// Only register producer method and producer field beans if the generic producer field has the same type as the generic bean declaration
if (genericConfiguration.getValue().getBaseType().equals(type.getKey().getBaseType()))
{
Expand Down Expand Up @@ -304,6 +330,11 @@ private <X> void addGenericProducer(Annotation genericConfiguration, AnnotatedMe
genericProducers.get(genericConfigurationType).put(genericConfiguration, annotatedMember);
}
}

private <T> void addOriginalProducer(Annotation genericConfiguration, Producer<T> producer)
{
originalProducers.put(genericConfiguration, producer);
}

private Bean<?> createGenericConfigurationBean(BeanManager beanManager, final Annotation genericConfiguration)
{
Expand All @@ -325,10 +356,37 @@ public Annotation create(Bean<Annotation> bean, CreationalContext<Annotation> ar
});
return builder.create();
}

private <T> Bean<T> createGenericProductBean(BeanManager beanManager, final Annotation genericConfiguration)
{
// We don't have a bean created for this generic configuration annotation. Create it, store it to be added later
Synthetic syntheticQualifier = productSyntheticProvider.get(genericConfiguration);
final Producer<T> producer = (Producer<T>) originalProducers.get(genericConfiguration);
AnnotatedMember<?> originalProducer = genericProducers.get(genericConfiguration.annotationType()).get(genericConfiguration);

// TODO make this passivation capable?
BeanBuilder<T> builder = new BeanBuilder<T>(beanManager)
.setJavaClass(Reflections.<T>getRawType(originalProducer.getBaseType()))
.setQualifiers(Arrays2.<Annotation> asSet(syntheticQualifier))
.setBeanLifecycle(new BeanLifecycle<T>()
{

public void destroy(Bean<T> bean, T instance, CreationalContext<T> ctx)
{
producer.dispose(instance);
}

public T create(Bean<T> bean, CreationalContext<T> ctx)
{
return producer.produce(ctx);
}
});
return builder.create();
}

private <X> Bean<X> createGenericBean(Bean<X> originalBean, Annotation genericConfiguration, AnnotatedType<X> type, BeanManager beanManager)
{
return new GenericManagedBean<X>(originalBean, genericConfiguration, (InjectionTarget<X>) genericInjectionTargets.get(genericConfiguration.annotationType()).get(type), type, syntheticProvider, beanManager);
return new GenericManagedBean<X>(originalBean, genericConfiguration, (InjectionTarget<X>) genericInjectionTargets.get(genericConfiguration.annotationType()).get(type), type, syntheticProvider, productSyntheticProvider, beanManager);
}

private <X, T> Bean<T> createGenericProducerMethod(Bean<T> originalBean, Annotation genericConfiguration, AnnotatedMethod<X> method, BeanManager beanManager)
Expand Down Expand Up @@ -369,6 +427,9 @@ void cleanup(@Observes AfterDeploymentValidation event)
this.genericProducers.clear();
this.genericBeans.clear();
this.syntheticProvider.clear();
this.genericBeanProducerFields.clear();
this.genericBeanProducerMethods.clear();
this.genericInjectionTargets.clear();
}

}
Expand Up @@ -25,14 +25,19 @@ class GenericManagedBean<T> extends AbstactGenericBean<T>
private final InjectionTarget<T> injectionTarget;
private final Map<AnnotatedField<? super T>, InjectionPoint> injectedFields;

GenericManagedBean(Bean<T> originalBean, Annotation genericConfiguration, InjectionTarget<T> injectionTarget, AnnotatedType<T> type, Synthetic.Provider syntheticProvider, BeanManager beanManager)
GenericManagedBean(Bean<T> originalBean, Annotation genericConfiguration, InjectionTarget<T> injectionTarget, AnnotatedType<T> type, Synthetic.Provider syntheticProvider, Synthetic.Provider productSyntheticProvider, BeanManager beanManager)
{
super(originalBean, Collections.<Annotation>singleton(syntheticProvider.get(genericConfiguration)), beanManager);
this.injectionTarget = injectionTarget;
this.injectedFields = new HashMap<AnnotatedField<? super T>, InjectionPoint>();
Synthetic genericProductQualifier = productSyntheticProvider.get(genericConfiguration);
for (AnnotatedField<? super T> field : type.getFields())
{
if (field.isAnnotationPresent(InjectGeneric.class))
if (field.isAnnotationPresent(InjectGeneric.class) && field.isAnnotationPresent(GenericProduct.class))
{
injectedFields.put(field, new InjectionPointImpl(field, Collections.<Annotation>singleton(genericProductQualifier), this, false, false));
}
else if (field.isAnnotationPresent(InjectGeneric.class))
{
injectedFields.put(field, new InjectionPointImpl(field, getQualifiers(), this, false, false));
}
Expand Down
@@ -0,0 +1,60 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.weld.extensions.bean.generic;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.enterprise.util.AnnotationLiteral;
import javax.inject.Qualifier;

/**
* Allows the product of the generic producer to be injected back into the generic bean
*
* <ul>
* <li>Only works on injected fields</li>
* </ul>
*
* @author Pete Muir
*
*/
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
@Qualifier
public @interface GenericProduct
{

static class GenericProductLiteral extends AnnotationLiteral<GenericProduct> implements GenericProduct
{

private static final long serialVersionUID = 2768505716290514234L;



private GenericProductLiteral() {}

}

static final GenericProduct INSTANCE = new GenericProductLiteral();

}
Expand Up @@ -19,6 +19,7 @@
import javax.enterprise.inject.Produces;
import javax.inject.Inject;

import org.jboss.weld.extensions.bean.generic.GenericProduct;
import org.jboss.weld.extensions.bean.generic.Generic;

/**
Expand Down Expand Up @@ -47,7 +48,7 @@ public Message getMessage()
return message;
}

@Produces @Qux
@Produces @GenericProduct
public String getBarMessage()
{
return "bar" + getInjectedMessage().value();
Expand Down
@@ -0,0 +1,50 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.weld.extensions.test.bean.generic.field;

import javax.enterprise.inject.Produces;
import javax.inject.Inject;

import org.jboss.weld.extensions.bean.generic.Generic;
import org.jboss.weld.extensions.bean.generic.GenericProduct;

/**
* A generic bean for the config annotation Message
*
* @author pmuir
*
*/

@Generic(Service.class)
public class Garply
{

@Inject @GenericProduct
private Waldo waldo;

@Produces @WaldoName
public String getWaldoName()
{
return waldo.getName();
}

public Waldo getWaldo()
{
return waldo;
}

}
Expand Up @@ -48,5 +48,29 @@ public class GenericBeanProducer
@Produces
@Message("bye2")
private Bar bar2;

@SuppressWarnings("unused")
@Foo(1)
@Produces
@Service(1)
private Waldo waldo1 = new Waldo("Pete");

@SuppressWarnings("unused")
@Foo(2)
@Produces
@Service(2)
private Waldo waldo2 = new Waldo("Stuart");

@SuppressWarnings("unused")
@Foo(1)
@Produces
@Service(1)
private Garply garply1;

@SuppressWarnings("unused")
@Foo(2)
@Produces
@Service(2)
private Garply garply2;

}

0 comments on commit 08b45af

Please sign in to comment.