Skip to content

Commit

Permalink
Specialization and tests
Browse files Browse the repository at this point in the history
git-svn-id: http://anonsvn.jboss.org/repos/weld/ri/trunk@1182 1c488680-804c-0410-94cd-c6b725194a0e
  • Loading branch information
pmuir committed Jan 23, 2009
1 parent 201c77b commit 9e56ce5
Show file tree
Hide file tree
Showing 21 changed files with 432 additions and 229 deletions.
141 changes: 141 additions & 0 deletions webbeans-ri/src/main/java/org/jboss/webbeans/BeanValidator.java
@@ -0,0 +1,141 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, 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.webbeans;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

import javax.webbeans.AmbiguousDependencyException;
import javax.webbeans.DefinitionException;
import javax.webbeans.InconsistentSpecializationException;
import javax.webbeans.InjectionPoint;
import javax.webbeans.New;
import javax.webbeans.NullableDependencyException;
import javax.webbeans.UnproxyableDependencyException;
import javax.webbeans.UnsatisfiedDependencyException;
import javax.webbeans.UnserializableDependencyException;
import javax.webbeans.manager.Bean;

import org.jboss.webbeans.bean.AbstractBean;
import org.jboss.webbeans.bean.NewEnterpriseBean;
import org.jboss.webbeans.bean.NewSimpleBean;
import org.jboss.webbeans.util.Beans;
import org.jboss.webbeans.util.ListComparator;
import org.jboss.webbeans.util.Proxies;
import org.jboss.webbeans.util.Reflections;

/**
* Checks a list of beans for DeploymentExceptions and their subclasses
*
* @author Nicklas Karlsson
*
*/
public class BeanValidator
{

private final ManagerImpl manager;

public BeanValidator(ManagerImpl manager)
{
this.manager = manager;
}

/**
* Validates the beans
*
* @param beans The beans to validate
*/
public void validate(List<Bean<?>> beans)
{
final List<Bean<?>> specializedBeans = new ArrayList<Bean<?>>();
for (Bean<?> bean : beans)
{
for (InjectionPoint injectionPoint : bean.getInjectionPoints())
{
if (injectionPoint.getType() instanceof Class)
{
Class<?> type = (Class<?>) injectionPoint.getType();
if (injectionPoint.getAnnotation(New.class) != null && injectionPoint.getBindings().size() > 1)
{
throw new DefinitionException("The injection point " + injectionPoint + " is annotated with @New which cannot be combined with other binding types");
}
Annotation[] bindings = injectionPoint.getBindings().toArray(new Annotation[0]);
Set<?> resolvedBeans = manager.resolveByType(type, bindings);
if (resolvedBeans.isEmpty())
{
throw new UnsatisfiedDependencyException("The injection point " + injectionPoint + " has unsatisfied dependencies for type " + type + " and binding types " + bindings + " in " + bean);
}
if (resolvedBeans.size() > 1)
{
throw new AmbiguousDependencyException("The injection point " + injectionPoint + " has ambiguos dependencies for type " + type + " and binding types " + bindings + " in " + bean);
}
Bean<?> resolvedBean = (Bean<?>) resolvedBeans.iterator().next();
if (MetaDataCache.instance().getScopeModel(resolvedBean.getScopeType()).isNormal() && !Proxies.isClassProxyable(type))
{
throw new UnproxyableDependencyException("The injection point " + injectionPoint + " has non-proxyable dependencies");
}
if (Reflections.isPrimitive((Class<?>) injectionPoint.getType()) && resolvedBean.isNullable())
{
throw new NullableDependencyException("The injection point " + injectionPoint + " has nullable dependencies");
}
}
else
{
throw new UnsupportedOperationException("Not yet implemented");
}
}
if (bean instanceof AbstractBean && !(bean instanceof NewSimpleBean) && !(bean instanceof NewEnterpriseBean))
{
AbstractBean<?, ?> abstractBean = (AbstractBean<?, ?>) bean;
if (abstractBean.isSpecializing())
{
if (!hasHigherPrecedence(bean.getDeploymentType(), abstractBean.getSpecializedBean().getDeploymentType()))
{
throw new InconsistentSpecializationException("Specializing bean must have a higher precedence deployment type than the specialized bean");
}
if (specializedBeans.contains(abstractBean.getSpecializedBean()))
{
throw new InconsistentSpecializationException("Two beans cannot specialize the same bean");
}
specializedBeans.add(abstractBean.getSpecializedBean());
}
}
if (Beans.isPassivatingBean(bean) && !bean.isSerializable())
{
throw new UnserializableDependencyException("The bean " + bean + " declares a passivating scopes but has non-serializable dependencies");
}
boolean normalScoped = MetaDataCache.instance().getScopeModel(bean.getScopeType()).isNormal();
if (normalScoped && !Beans.isBeanProxyable(bean))
{
throw new UnproxyableDependencyException("Normal scoped bean " + bean + " is not proxyable");
}
}

}


private boolean hasHigherPrecedence(Class<? extends Annotation> deploymentType, Class<? extends Annotation> otherDeploymentType)
{
Comparator<Class<? extends Annotation>> comparator = new ListComparator<Class<? extends Annotation>>(manager.getEnabledDeploymentTypes());
return comparator.compare(deploymentType, otherDeploymentType) > 0;
}


}
4 changes: 2 additions & 2 deletions webbeans-ri/src/main/java/org/jboss/webbeans/ManagerImpl.java
Expand Up @@ -64,7 +64,7 @@
import org.jboss.webbeans.introspector.jlr.AnnotatedClassImpl;
import org.jboss.webbeans.resources.spi.NamingContext;
import org.jboss.webbeans.resources.spi.ResourceLoader;
import org.jboss.webbeans.util.Proxies;
import org.jboss.webbeans.util.Beans;
import org.jboss.webbeans.util.Reflections;

/**
Expand Down Expand Up @@ -623,7 +623,7 @@ else if (beans.size() > 1)
}
Bean<T> bean = beans.iterator().next();
boolean normalScoped = MetaDataCache.instance().getScopeModel(bean.getScopeType()).isNormal();
if (normalScoped && !Proxies.isBeanProxyable(bean))
if (normalScoped && !Beans.isBeanProxyable(bean))
{
throw new UnproxyableDependencyException("Normal scoped bean " + bean + " is not proxyable");
}
Expand Down
Expand Up @@ -43,7 +43,7 @@
import org.jboss.webbeans.log.LogProvider;
import org.jboss.webbeans.log.Logging;
import org.jboss.webbeans.model.MergedStereotypes;
import org.jboss.webbeans.util.Proxies;
import org.jboss.webbeans.util.Beans;
import org.jboss.webbeans.util.Reflections;

/**
Expand Down Expand Up @@ -139,6 +139,12 @@ protected void init()
initTypes();
initProxyable();
checkRequiredTypesImplemented();
if (isSpecializing())
{
preCheckSpecialization();
initSpecialization();
postCheckSpecialization();
}
}

/**
Expand All @@ -157,6 +163,10 @@ protected void initBindingTypes()
{
this.bindingTypes = new HashSet<Annotation>();
this.bindingTypes.addAll(getAnnotatedItem().getMetaAnnotations(BindingType.class));
if (isSpecializing())
{
this.bindingTypes.addAll(getSpecializedBean().getBindings());
}
if (bindingTypes.size() == 0)
{
log.trace("Adding default @Current binding type");
Expand Down Expand Up @@ -213,7 +223,11 @@ protected void initName()
return;
}
}

else if (isSpecializing())
{
this.name = getSpecializedBean().getName();
return;
}

if (beanNameDefaulted || getMergedStereotypes().isBeanNameDefaulted())
{
Expand All @@ -224,7 +238,7 @@ protected void initName()

protected void initProxyable()
{
proxyable = Proxies.apiTypesAreProxyable(getTypes());
proxyable = Beans.apiTypesAreProxyable(getTypes());
}

/**
Expand Down Expand Up @@ -309,6 +323,24 @@ protected void checkRequiredTypesImplemented()
}
}
}

protected void postCheckSpecialization()
{
if (getAnnotatedItem().isAnnotationPresent(Named.class) && getSpecializedBean().getAnnotatedItem().isAnnotationPresent(Named.class))
{
throw new DefinitionException("Cannot put name on specializing and specialized class");
}
}

protected void preCheckSpecialization()
{

}

protected void initSpecialization()
{

}

/**
* Binds the decorators to the proxy
Expand Down Expand Up @@ -373,6 +405,10 @@ protected Type getDeclaredBeanType()
* @return The default name
*/
protected abstract String getDefaultName();

public abstract AbstractBean<?, ?> getSpecializedBean();

public abstract boolean isSpecializing();

/**
* Gets the deployment type of the bean
Expand Down Expand Up @@ -520,4 +556,18 @@ public boolean isProxyable()
{
return proxyable;
}

@Override
public boolean equals(Object other)
{
if (other instanceof AbstractBean)
{
AbstractBean<?, ?> that = (AbstractBean<?, ?>) other;
return this.getTypes().equals(that.getTypes()) && this.getBindings().equals(that.getBindings());
}
else
{
return false;
}
}
}
Expand Up @@ -70,11 +70,11 @@ public abstract class AbstractClassBean<T> extends AbstractBean<T, Class<T>>
* @param type The type
* @param manager The Web Beans manager
*/
public AbstractClassBean(AnnotatedClass<T> type, ManagerImpl manager)
protected AbstractClassBean(AnnotatedClass<T> type, ManagerImpl manager)
{
super(manager);
this.annotatedItem = type;
dependentInstancesStore = new DependentInstancesStore();
this.dependentInstancesStore = new DependentInstancesStore();
}

/**
Expand Down Expand Up @@ -270,6 +270,22 @@ protected void checkBeanImplementation()
throw new DefinitionException("Web Bean implementation class " + type + " cannot be declared abstract");
}
}

@Override
protected void preCheckSpecialization()
{
super.preCheckSpecialization();
if (getAnnotatedItem().getSuperclass() == null || getAnnotatedItem().getSuperclass().getType().equals(Object.class))
{
throw new DefinitionException("Specializing bean must extend another bean");
}
}

@Override
public boolean isSpecializing()
{
return getAnnotatedItem().isAnnotationPresent(Specializes.class);
}

/**
* Gets the annotated item
Expand All @@ -290,22 +306,10 @@ protected AnnotatedClass<T> getAnnotatedItem()
@Override
protected String getDefaultName()
{
String name = Strings.decapitalize(getSpecializedType().getSimpleName());
String name = Strings.decapitalize(getAnnotatedItem().getSimpleName());
log.trace("Default name of " + type + " is " + name);
return name;
}

private AnnotatedClass<?> getSpecializedType()
{
if (annotatedItem.isAnnotationPresent(Specializes.class))
{
return annotatedItem.getSuperclass();
}
else
{
return annotatedItem;
}
}

/**
* Gets the injectable fields
Expand Down
Expand Up @@ -159,5 +159,17 @@ public String toString()
{
return "FacadeBean " + getName() + " for " + annotatedItem;
}

@Override
public AbstractBean<?, ?> getSpecializedBean()
{
return null;
}

@Override
public boolean isSpecializing()
{
return false;
}

}
Expand Up @@ -37,6 +37,7 @@
import org.jboss.webbeans.injection.InjectionPointImpl;
import org.jboss.webbeans.log.LogProvider;
import org.jboss.webbeans.log.Logging;
import org.jboss.webbeans.util.Beans;
import org.jboss.webbeans.util.Names;
import org.jboss.webbeans.util.Reflections;

Expand Down Expand Up @@ -176,7 +177,7 @@ protected void checkReturnValue(T instance)
{
return;
}
if (dependent && Reflections.isPassivatingBean(injectionPoint.getBean()))
if (dependent && Beans.isPassivatingBean(injectionPoint.getBean()))
{
if (injectionPoint.isField())
{
Expand Down

0 comments on commit 9e56ce5

Please sign in to comment.