/*******************************************************************************
* Copyright (c) 2009-2014 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.cdi.internal.core.validation;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.JavaConventions;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jface.text.IRegion;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.common.componentcore.ComponentCore;
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
import org.eclipse.wst.common.componentcore.resources.IVirtualFile;
import org.eclipse.wst.validation.internal.core.ValidationException;
import org.eclipse.wst.validation.internal.operations.WorkbenchReporter;
import org.eclipse.wst.validation.internal.provisional.core.IReporter;
import org.eclipse.wst.validation.internal.provisional.core.IValidationContext;
import org.eclipse.wst.validation.internal.provisional.core.IValidator;
import org.jboss.tools.cdi.core.CDIConstants;
import org.jboss.tools.cdi.core.CDICoreBuilder;
import org.jboss.tools.cdi.core.CDICoreNature;
import org.jboss.tools.cdi.core.CDICorePlugin;
import org.jboss.tools.cdi.core.CDIUtil;
import org.jboss.tools.cdi.core.CDIVersion;
import org.jboss.tools.cdi.core.IBean;
import org.jboss.tools.cdi.core.IBeanMethod;
import org.jboss.tools.cdi.core.ICDIAnnotation;
import org.jboss.tools.cdi.core.ICDIElement;
import org.jboss.tools.cdi.core.ICDIProject;
import org.jboss.tools.cdi.core.IClassBean;
import org.jboss.tools.cdi.core.IDecorator;
import org.jboss.tools.cdi.core.IInitializerMethod;
import org.jboss.tools.cdi.core.IInjectionPoint;
import org.jboss.tools.cdi.core.IInjectionPointField;
import org.jboss.tools.cdi.core.IInjectionPointParameter;
import org.jboss.tools.cdi.core.IInterceptor;
import org.jboss.tools.cdi.core.IInterceptorBinded;
import org.jboss.tools.cdi.core.IInterceptorBinding;
import org.jboss.tools.cdi.core.IInterceptorBindingDeclaration;
import org.jboss.tools.cdi.core.IParameter;
import org.jboss.tools.cdi.core.IProducer;
import org.jboss.tools.cdi.core.IProducerField;
import org.jboss.tools.cdi.core.IProducerMethod;
import org.jboss.tools.cdi.core.IQualifier;
import org.jboss.tools.cdi.core.IQualifierDeclaration;
import org.jboss.tools.cdi.core.IScope;
import org.jboss.tools.cdi.core.IScopeDeclaration;
import org.jboss.tools.cdi.core.ISessionBean;
import org.jboss.tools.cdi.core.IStereotype;
import org.jboss.tools.cdi.core.IStereotypeDeclaration;
import org.jboss.tools.cdi.core.IStereotyped;
import org.jboss.tools.cdi.core.extension.feature.IBeanKeyProvider;
import org.jboss.tools.cdi.core.extension.feature.IInjectionPointValidatorFeature;
import org.jboss.tools.cdi.core.extension.feature.IValidatorFeature;
import org.jboss.tools.cdi.core.preferences.CDIPreferences;
import org.jboss.tools.cdi.internal.core.impl.CDIDisposedException;
import org.jboss.tools.cdi.internal.core.impl.CDIProject;
import org.jboss.tools.cdi.internal.core.impl.CDIProjectAsYouType;
import org.jboss.tools.cdi.internal.core.impl.ClassBean;
import org.jboss.tools.cdi.internal.core.impl.SessionBean;
import org.jboss.tools.cdi.internal.core.impl.definition.Dependencies;
import org.jboss.tools.common.EclipseUtil;
import org.jboss.tools.common.java.IAnnotationDeclaration;
import org.jboss.tools.common.java.IJavaReference;
import org.jboss.tools.common.java.IParametedType;
import org.jboss.tools.common.java.ITypeDeclaration;
import org.jboss.tools.common.java.ParametedType;
import org.jboss.tools.common.model.util.EclipseJavaUtil;
import org.jboss.tools.common.model.util.EclipseResourceUtil;
import org.jboss.tools.common.text.INodeReference;
import org.jboss.tools.common.text.ITextSourceReference;
import org.jboss.tools.common.validation.ContextValidationHelper;
import org.jboss.tools.common.validation.EditorValidationContext;
import org.jboss.tools.common.validation.IJavaElementValidator;
import org.jboss.tools.common.validation.IPreferenceInfo;
import org.jboss.tools.common.validation.IProjectValidationContext;
import org.jboss.tools.common.validation.IStringValidator;
import org.jboss.tools.common.validation.ITypedReporter;
import org.jboss.tools.common.validation.IValidatingProjectSet;
import org.jboss.tools.common.validation.IValidatingProjectTree;
import org.jboss.tools.common.validation.PreferenceInfoManager;
import org.jboss.tools.common.validation.ValidationUtil;
import org.jboss.tools.common.validation.ValidatorManager;
import org.jboss.tools.jst.web.kb.internal.validation.KBValidator;
/**
* @author Alexey Kazakov
*/
public class CDICoreValidator extends CDIValidationErrorManager implements IJavaElementValidator, IStringValidator {
public static final String ID = "org.jboss.tools.cdi.core.CoreValidator"; //$NON-NLS-1$
public static final String PREFERENCE_PAGE_ID = "org.jboss.tools.cdi.ui.preferences.CDIValidatorPreferencePage"; //$NON-NLS-1$
public static final String PROPERTY_PAGE_ID = "org.jboss.tools.cdi.ui.propertyPages.CDIValidatorPreferencePage"; //$NON-NLS-1$
ICDIProject rootCdiProject;
Map<IProject, CDIValidationContext> cdiContexts = new HashMap<IProject, CDIValidationContext>();
String rootProjectName;
IValidatingProjectTree projectTree;
IValidatingProjectSet projectSet;
Set<IFolder> sourceFolders;
List<IFile> allBeansXmls;
boolean missingBeansXmlValidated;
private BeansXmlValidationDelegate beansXmlValidator = new BeansXmlValidationDelegate(this);
private AnnotationValidationDelegate annotationValidator = new AnnotationValidationDelegate(this);
public static final String SHORT_ID = "jboss.cdi.core"; //$NON-NLS-1$
public static class CDIValidationContext {
private ICDIProject cdiProject;
private IProject project;
private Dependencies dependencies;
private Set<IValidatorFeature> extensions;
private Set<IInjectionPointValidatorFeature> injectionValidationFeatures;
public CDIValidationContext(IProject project, ICDIProject cdiProject) {
this.project = project;
this.cdiProject = cdiProject;
dependencies = new Dependencies();
extensions = Collections.emptySet();
injectionValidationFeatures = cdiProject.getNature().getExtensionManager().getFeatures(IInjectionPointValidatorFeature.class);
}
public CDIValidationContext(IProject project) {
this.project = project;
CDICoreNature nature = CDICorePlugin.getCDI(project, true);
if(nature == null) {
throw new CDIDisposedException();
}
cdiProject = nature.getDelegate();
dependencies = nature.getDefinitions().getAllDependencies();
extensions = nature.getExtensionManager().getValidatorFeatures();
injectionValidationFeatures = nature.getExtensionManager().getFeatures(IInjectionPointValidatorFeature.class);
}
/**
* @return the cdiProject
*/
public ICDIProject getCdiProject() {
return cdiProject;
}
/**
* @return the project
*/
public IProject getProject() {
return project;
}
/**
* @return the dependencies
*/
public Dependencies getDependencies() {
return dependencies;
}
/**
* @return the extensions
*/
public Set<IValidatorFeature> getExtensions() {
return extensions;
}
/**
* @return the injection validation features
*/
public Set<IInjectionPointValidatorFeature> getInjectionValidationFeatures() {
return injectionValidationFeatures;
}
}
CDIValidationContext getCDIContext(IResource resource) {
IProject project = resource.getProject();
CDIValidationContext context = cdiContexts.get(project);
if(context==null) {
context = new CDIValidationContext(project);
cdiContexts.put(project, context);
}
return context;
}
/*
* (non-Javadoc)
*
* @see org.jboss.tools.jst.web.kb.validation.IValidator#getId()
*/
public String getId() {
return ID;
}
public String getBuilderId() {
return CDICoreBuilder.BUILDER_ID;
}
/*
* (non-Javadoc)
*
* @see
* org.jboss.tools.jst.web.kb.validation.IValidator#getValidatingProjects
* (org.eclipse.core.resources.IProject)
*/
public IValidatingProjectTree getValidatingProjects(IProject project) {
projectTree = getProjectTree(project);
return projectTree;
}
public static IValidatingProjectTree getProjectTree(IProject project) {
return new CDIProjectTree(project);
}
/*
* (non-Javadoc)
* @see org.jboss.tools.jst.web.kb.validation.IValidator#isEnabled(org.eclipse.core.resources.IProject)
*/
public boolean isEnabled(IProject project) {
return CDIPreferences.isValidationEnabled(project);
}
/*
* (non-Javadoc)
*
* @see
* org.jboss.tools.jst.web.kb.validation.IValidator#shouldValidate(org.eclipse
* .core.resources.IProject)
*/
public boolean shouldValidate(IProject project) {
return shouldValidate(project, false);
}
@Override
public boolean shouldValidateAsYouType(IProject project) {
return shouldValidate(project, true);
}
public boolean shouldValidate(IProject project, boolean asYouType) {
try {
return project.isAccessible()
&& project.hasNature(CDICoreNature.NATURE_ID)
&& isEnabled(project)
&& (asYouType || validateBuilderOrder(project));
} catch (CoreException e) {
CDICorePlugin.getDefault().logError(e);
}
return false;
}
private boolean validateBuilderOrder(IProject project) throws CoreException {
return KBValidator.validateBuilderOrder(project, getBuilderId(), getId(), CDIPreferences.getInstance());
}
/*
* (non-Javadoc)
* @see org.jboss.tools.jst.web.kb.internal.validation.ValidationErrorManager#init(org.eclipse.core.resources.IProject, org.jboss.tools.jst.web.kb.internal.validation.ContextValidationHelper, org.jboss.tools.jst.web.kb.validation.IProjectValidationContext, org.eclipse.wst.validation.internal.provisional.core.IValidator, org.eclipse.wst.validation.internal.provisional.core.IReporter)
*/
@Override
public void init(IProject rootProject, ContextValidationHelper validationHelper, IProjectValidationContext context, org.eclipse.wst.validation.internal.provisional.core.IValidator manager,
IReporter reporter) {
try {
super.init(rootProject, validationHelper, context, manager, reporter);
setAsYouTypeValidation(false);
projectTree = validationHelper.getValidationContextManager().getValidatingProjectTree(this);
projectSet = projectTree.getBrunches().get(rootProject);
rootCdiProject = null;
allBeansXmls = null;
missingBeansXmlValidated = false;
CDICoreNature nature = CDICorePlugin.getCDI(projectSet.getRootProject(), true);
if(nature!=null) {
rootCdiProject = nature.getDelegate();
if(rootCdiProject==null) {
CDICorePlugin.getDefault().logError("Trying to validate " + rootProject + " but CDI Tools model for the project is not built.");
}
} else {
CDICorePlugin.getDefault().logError("Trying to validate " + rootProject + " but there is no CDI Nature in the project.");
}
rootProjectName = projectSet.getRootProject().getName();
cdiContexts.clear();
} catch (CDIDisposedException e) {
//Do nothing, the nature or project is disposed.
}
}
/*
* (non-Javadoc)
* @see org.jboss.tools.jst.web.kb.validation.IValidator#validate(java.util.Set, org.eclipse.core.resources.IProject, org.jboss.tools.jst.web.kb.internal.validation.ContextValidationHelper, org.jboss.tools.jst.web.kb.validation.IProjectValidationContext, org.jboss.tools.jst.web.kb.internal.validation.ValidatorManager, org.eclipse.wst.validation.internal.provisional.core.IReporter)
*/
@Override
public IStatus validate(Set<IFile> changedFiles, IProject project, ContextValidationHelper validationHelper, IProjectValidationContext context, ValidatorManager manager, IReporter reporter)
throws ValidationException {
try {
init(project, validationHelper, context, manager, reporter);
displaySubtask(CDIValidationMessages10.SEARCHING_RESOURCES, new String[]{project.getName()});
if (rootCdiProject == null) {
return OK_STATUS;
}
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
Set<IPath> resources = new HashSet<IPath>(); // Resources which we have
// to validate.
boolean hasDotProject = false;
Set<IPath> resourcesToClean = new HashSet<IPath>(); // Resource which we should remove from validation context
for(IFile file: changedFiles) {
resourcesToClean.add(file.getFullPath());
Set<IPath> dd = getCDIContext(file).getDependencies().getDirectDependencies(file.getFullPath());
if(dd != null) {
for (IPath p: dd) {
IFile f = root.getFile(p);
if(f.exists() && !changedFiles.contains(f)) {
resources.add(p);
collectAllRelatedInjections(f, resources);
}
}
}
if(file.getName().endsWith(".project")) {
hasDotProject = true;
}
}
for (IFile currentFile : changedFiles) {
if (reporter.isCancelled()) {
break;
}
if (ValidationUtil.checkFileExtensionForJavaAndXml(currentFile)) {
resources.add(currentFile.getFullPath());
Set<String> newElNamesOfChangedFile = getELNamesByResource(getCDIContext(currentFile), currentFile.getFullPath());
for (String newElName : newElNamesOfChangedFile) {
// Collect resources that had EL names (in previous validation session) declared in this changed resource.
Set<IPath> linkedResources = validationContext.getCoreResourcesByVariableName(SHORT_ID, newElName, true);
if(linkedResources!=null) {
resources.addAll(linkedResources);
}
}
// Get old EL names which were linked with this resource in previous validation session.
Set<String> oldElNamesOfChangedFile = validationContext.getVariableNamesByCoreResource(SHORT_ID, currentFile.getFullPath(), true);
if(oldElNamesOfChangedFile!=null) {
for (String name : oldElNamesOfChangedFile) {
Set<IPath> linkedResources = validationContext.getCoreResourcesByVariableName(SHORT_ID, name, true);
if(linkedResources!=null) {
resources.addAll(linkedResources);
}
// Save old (from previous validation session) EL names. We need to validate all the resources which use this old EL name in case the name has been changed.
validationContext.addVariableNameForELValidation(SHORT_ID, name);
}
}
collectAllRealtedCoreResources(currentFile, resources);
collectAllRelatedResourcesFromPackageInfo(currentFile, resources);
}
}
Set<IFile> filesToValidate = new HashSet<IFile>();
for (IPath linkedResource : resources) {
IFile file = root.getFile(linkedResource);
if(shouldBeValidated(file)) {
IProject pr = file.getProject();
if(!validationHelper.getValidationContextManager().projectHasBeenValidated(this, pr)) {
filesToValidate.add(file);
}
}
}
// Validate all collected linked resources.
// Remove all links between collected resources because they will be
// linked again during validation.
resourcesToClean.addAll(resources);
getValidationContext().removeLinkedCoreResources(SHORT_ID, resourcesToClean);
// We should remove markers from the source files at first
for(IFile file: filesToValidate) {
removeAllMessagesFromResource(file);
}
validateRemovedFiles(project, context);
// Then we can validate them
for (IFile file : filesToValidate) {
validateResource(file);
}
if(hasDotProject) {
validateMissingBeansXml();
}
} catch (CDIDisposedException e) {
//Do nothing, the nature or project is disposed.
}
cleanSavedMarkers();
return OK_STATUS;
}
private void validateRemovedFiles(IProject project, IProjectValidationContext context) {
// Validate if beans.xml is now missing
Set<IFile> files = context.getValidationResourceRegister().getRemovedFiles();
for (IFile file : files) {
if(file.getName().equals("beans.xml")) {
validateMissingBeansXml();
break;
}
}
}
private void validateMissingBeansXml() {
if(!missingBeansXmlValidated && !isAsYouTypeValidation()) {
List<IFile> beansXmls = getAllBeansXmls();
Set<String> projectsWithBeansXml = new HashSet<String>();
for (IFile beansXml : beansXmls) {
projectsWithBeansXml.add(beansXml.getProject().getName());
}
Set<IProject> allProjects = projectSet.getAllProjects();
for (IProject project : allProjects) {
removeAllMessagesFromProject(project);
CDIValidationContext context = getCDIContext(project);
// Report missing beans.xml only for CDI 1.0 projects
if(context.getCdiProject().getVersion() == CDIVersion.CDI_1_0
&& !projectsWithBeansXml.contains(project.getName())) {
reportMissingBeansXml(project, CDIVersion.CDI_1_0);
}
}
missingBeansXmlValidated = true;
}
}
private void collectAllRealtedCoreResources(IFile validatingResource, Set<IPath> relatedResources) {
// Get all the paths of related resources for given file. These
// links were saved in previous validation process.
Set<String> oldReletedResources = getValidationContext().getVariableNamesByCoreResource(SHORT_ID, validatingResource.getFullPath(), false);
if (oldReletedResources != null) {
for (String resourcePath : oldReletedResources) {
if(resourcePath.startsWith("/") || resourcePath.startsWith("\\")) {
relatedResources.add(Path.fromOSString(resourcePath));
}
}
}
collectAllRelatedInjections(validatingResource, relatedResources);
}
/*
* (non-Javadoc)
* @see org.jboss.tools.jst.web.kb.validation.IValidator#validateAll(org.eclipse.core.resources.IProject, org.jboss.tools.jst.web.kb.internal.validation.ContextValidationHelper, org.jboss.tools.jst.web.kb.validation.IProjectValidationContext, org.jboss.tools.jst.web.kb.internal.validation.ValidatorManager, org.eclipse.wst.validation.internal.provisional.core.IReporter)
*/
@Override
public IStatus validateAll(IProject project, ContextValidationHelper validationHelper, IProjectValidationContext context, ValidatorManager manager, IReporter reporter)
throws ValidationException {
init(project, validationHelper, context, manager, reporter);
if (rootCdiProject == null) {
return OK_STATUS;
}
for (IProject iProject : projectSet.getAllProjects()) {
if(notValidatedYet(iProject)) {
removeAllMessagesFromResource(iProject);
}
}
displaySubtask(CDIValidationMessages10.VALIDATING_PROJECT, new String[] {rootProjectName});
Set<IFile> filesToValidate = new HashSet<IFile>();
IBean[] beans = rootCdiProject.getBeans();
for (IBean bean : beans) {
IResource resource = bean.getResource();
if(resource!=null && shouldValidateType(bean.getBeanClass()) && notValidatedYet(resource)) {
filesToValidate.add((IFile)resource);
}
}
IStereotype[] stereotypes = rootCdiProject.getStereotypes();
for (IStereotype stereotype : stereotypes) {
IResource resource = stereotype.getResource();
if(shouldValidateResourceOfElement(resource) && notValidatedYet(resource)) {
filesToValidate.add((IFile)resource);
}
}
IQualifier[] qualifiers = rootCdiProject.getQualifiers();
for (IQualifier qualifier : qualifiers) {
IResource resource = qualifier.getResource();
if(shouldValidateResourceOfElement(resource) && notValidatedYet(resource)) {
filesToValidate.add((IFile)resource);
}
}
IInterceptorBinding[] bindings = rootCdiProject.getInterceptorBindings();
for (IInterceptorBinding binding : bindings) {
IResource resource = binding.getResource();
if(shouldValidateResourceOfElement(resource) && notValidatedYet(resource)) {
filesToValidate.add((IFile)resource);
}
}
for (String scopeName: rootCdiProject.getScopeNames()) {
IScope scope = rootCdiProject.getScope(scopeName);
IResource resource = scope.getResource();
if(shouldValidateResourceOfElement(resource) && notValidatedYet(resource)) {
filesToValidate.add((IFile)resource);
}
}
List<IFile> beansXmls = getAllBeansXmls();
for (IFile beansXml : beansXmls) {
if(notValidatedYet(beansXml)) {
filesToValidate.add(beansXml);
}
}
// We should remove markers from the source files at first
for(IFile file: filesToValidate) {
removeAllMessagesFromResource(file);
}
for (IFile file : filesToValidate) {
validateResource(file);
}
validateMissingBeansXml();
cleanSavedMarkers();
return OK_STATUS;
}
/**
* Removes all the validation problems created by this validator
* @param project
*/
public static void cleanProject(IProject project) {
WorkbenchReporter.removeAllMessages(project, new String[]{CDICoreValidator.class.getName()}, null);
}
/*
* (non-Javadoc)
* @see org.jboss.tools.common.validation.IAsYouTypeValidator#validate(org.eclipse.wst.validation.internal.provisional.core.IValidator, org.eclipse.core.resources.IProject, org.eclipse.jface.text.IRegion, org.eclipse.wst.validation.internal.provisional.core.IValidationContext, org.eclipse.wst.validation.internal.provisional.core.IReporter, org.jboss.tools.common.validation.EditorValidationContext, org.jboss.tools.common.validation.IProjectValidationContext, org.eclipse.core.resources.IFile)
*/
@Override
public void validate(IValidator validatorManager, IProject rootProject, Collection<IRegion> dirtyRegions, IValidationContext helper, IReporter reporter, EditorValidationContext validationContext, IProjectValidationContext projectContext, final IFile file) {
ContextValidationHelper validationHelper = new ContextValidationHelper();
validationHelper.setProject(rootProject);
validationHelper.setValidationContextManager(validationContext);
init(rootProject, validationHelper, projectContext, validatorManager, reporter);
setAsYouTypeValidation(true);
asYouTypeTimestamp++;
this.document = validationContext.getDocument();
if(rootCdiProject == null) {
return;
}
rootCdiProject = new CDIProjectAsYouType(rootCdiProject, file);
validateResource(file);
if(reporter instanceof ITypedReporter) {
((ITypedReporter)reporter).addTypeForFile(getProblemType());
}
disableProblemAnnotations(new IRegion() {
@Override
public int getOffset() {
return 0;
}
@Override
public int getLength() {
return document.getLength();
}
}, reporter);
}
/**
* Validates a resource.
*
* @param file
*/
private void validateResource(IFile file) {
if (reporter.isCancelled() || !file.isAccessible()) {
return;
}
displaySubtask(CDIValidationMessages10.VALIDATING_RESOURCE, new String[] {file.getProject().getName(), file.getName()});
if(!isAsYouTypeValidation()) {
coreHelper.getValidationContextManager().addValidatedProject(this, file.getProject());
Set<IPath> dd = getCDIContext(file).getDependencies().getDirectDependencies(file.getFullPath());
if(dd != null && !dd.isEmpty()) {
Set<IPath> resources = new HashSet<IPath>();
for (IPath p: dd) {
IFile f = ResourcesPlugin.getWorkspace().getRoot().getFile(p);
if(f.exists()) {
resources.add(p);
collectAllRelatedInjections(f, resources);
}
}
for (IPath p: resources) {
getValidationContext().addLinkedCoreResource(SHORT_ID, p.toString(), file.getFullPath(), false);
}
}
}
CDIValidationContext context = null;
ICDIProject cdiProject = null;
if(isAsYouTypeValidation()) {
context = new CDIValidationContext(file.getProject(), rootCdiProject);
cdiProject = rootCdiProject;
} else {
context = getCDIContext(file);
cdiProject = context.getCdiProject();
}
if("beans.xml".equalsIgnoreCase(file.getName())) {
validateMissingBeansXml();
if(CDIPreferences.shouldValidateBeansXml(file.getProject())) {
List<IFile> allBaensXmls = getAllBeansXmls();
if(allBaensXmls.contains(file)) { // See https://issues.jboss.org/browse/JBIDE-10166
beansXmlValidator.validateBeansXml(context, file);
}
}
} else {
Collection<IBean> beans = cdiProject.getBeans(file.getFullPath());
for (IBean bean : beans) {
validateBean(context, bean);
}
IStereotype stereotype = cdiProject.getStereotype(file.getFullPath());
validateStereotype(stereotype);
IQualifier qualifier = cdiProject.getQualifier(file.getFullPath());
validateQualifier(qualifier);
IScope scope = cdiProject.getScope(file.getFullPath());
annotationValidator.validateScopeType(scope);
IInterceptorBinding binding = cdiProject.getInterceptorBinding(file.getFullPath());
validateInterceptorBinding(binding);
}
Set<IValidatorFeature> extensions = context.getExtensions();
for (IValidatorFeature v: extensions) {
setSeverityPreferences(v.getSeverityPreferences());
v.validateResource(file, this);
setSeverityPreferences(null);
}
}
private void reportMissingBeansXml(IProject project, CDIVersion version) {
addProblem(MessageFormat.format(CDIValidationMessages.MISSING_BEANS_XML[version.getIndex()], project.getName()), CDIPreferences.MISSING_BEANS_XML, new ITextSourceReference() {
@Override
public int getStartPosition() {
return 0;
}
@Override
public int getLength() {
return 0;
}
@Override
public IResource getResource() {
return null;
}
}, project, MISSING_BEANS_XML_ID);
}
Set<IFolder> getSourceFoldersForProjectsSet() {
if(sourceFolders==null) {
sourceFolders = new HashSet<IFolder>();
Set<IProject> projects = projectSet.getAllProjects();
for (IProject project : projects) {
sourceFolders.addAll(EclipseResourceUtil.getSourceFolders(project));
}
}
return sourceFolders;
}
/**
* Returns all the beans.xml from META-INF and WEB-INF folders
*
* @return
*/
private List<IFile> getAllBeansXmls() {
if(allBeansXmls==null) {
allBeansXmls = new ArrayList<IFile>();
// From source folders
Set<IFolder> sourceFolders = getSourceFoldersForProjectsSet();
for (IFolder source : sourceFolders) {
IResource beansXml = source.findMember(new Path("/META-INF/beans.xml")); //$NON-NLS-1$
if(beansXml instanceof IFile) {
allBeansXmls.add((IFile)beansXml);
}
}
Set<IProject> allProjects = projectSet.getAllProjects();
for (IProject project : allProjects) {
// From WEB-INF folder
IVirtualComponent com = ComponentCore.createComponent(project);
if(com!=null) {
IVirtualFile beansXml = com.getRootFolder().getFile(new Path("/WEB-INF/beans.xml")); //$NON-NLS-1$
if(beansXml!=null && beansXml.getUnderlyingFile().isAccessible()) {
allBeansXmls.add(beansXml.getUnderlyingFile());
}
}
}
}
return allBeansXmls;
}
/**
* Validates a bean.
*
* @param bean
*/
private void validateBean(CDIValidationContext context, IBean bean) {
if (reporter.isCancelled()) {
return;
}
if(!bean.exists() || !shouldValidateType(bean.getBeanClass())) {
return;
}
String beanPath = null;
if(!isAsYouTypeValidation()) {
beanPath = bean.getSourcePath().toString();
Collection<IScopeDeclaration> scopeDeclarations = bean.getScopeDeclarations();
for (IScopeDeclaration scopeDeclaration : scopeDeclarations) {
IScope scope = scopeDeclaration.getScope();
if (shouldValidateType(scope.getSourceType())) {
getValidationContext().addLinkedCoreResource(SHORT_ID, beanPath, scope.getSourcePath(), false);
}
}
addLinkedStereotypes(beanPath, bean);
Collection<IQualifierDeclaration> qualifierDeclarations = bean.getQualifierDeclarations();
for (IQualifierDeclaration qualifierDeclaration : qualifierDeclarations) {
IQualifier qualifier = qualifierDeclaration.getQualifier();
if (qualifier != null && shouldValidateType(qualifier.getSourceType())) {
getValidationContext().addLinkedCoreResource(SHORT_ID, beanPath, qualifier.getSourcePath(), false);
}
}
}
// validate
validateTyped(bean);
validateBeanScope(bean);
validateNormalBeanScope(bean);
if (bean instanceof IProducer) {
validateProducer(context, (IProducer) bean);
}
Collection<IInjectionPoint> points = bean instanceof IClassBean? ((IClassBean)bean).getInjectionPoints(false):bean.getInjectionPoints();
for (IInjectionPoint point : points) {
if(!isAsYouTypeValidation()) {
IType type = getTypeOfInjection(point);
if(type!=null && !type.isBinary()) {
getValidationContext().addLinkedCoreResource(SHORT_ID, beanPath, type.getPath(), false);
}
}
if(point.exists()) {
validateInjectionPoint(context, point);
}
}
if (bean instanceof IInterceptor) {
validateInterceptor((IInterceptor) bean);
}
if (bean instanceof IDecorator) {
validateDecorator(context, (IDecorator) bean);
}
if (bean instanceof IClassBean) {
IClassBean classBean = (IClassBean)bean;
if(!isAsYouTypeValidation()) {
addLinkedInterceptorBindings(beanPath, classBean);
Collection<IBeanMethod> methods = classBean.getAllMethods();
for (IBeanMethod method : methods) {
addLinkedStereotypes(beanPath, method);
addLinkedInterceptorBindings(beanPath, method);
}
}
validateClassBean(classBean);
}
validateSpecializingBean(bean);
validateBeanName(context, bean);
}
/**
* Validates a bean EL name.
*
* @param bean
*/
private void validateBeanName(CDIValidationContext context, IBean bean) {
String name = bean.getName();
if(name!=null && !name.startsWith("/")) {
if(!isAsYouTypeValidation()) {
// Collect all relations between the bean and other CDI elements.
getValidationContext().addVariableNameForELValidation(SHORT_ID, name);
getValidationContext().addLinkedCoreResource(SHORT_ID, name, bean.getSourcePath(), true);
}
/*
* 5.3.1. Ambiguous EL names
* - All unresolvable ambiguous EL names are detected by the container when the application is initialized.
* Suppose two beans are both available for injection in a certain war, and either:
* • the two beans have the same EL name and the name is not resolvable, or
*/
Collection<IBean> beans = context.getCdiProject().getBeans(name, true);
if(beans.size()>1 && beans.contains(bean)) {
// We need to sort bean element names to make sure we report the same problem message for the same bean name for every validation process.
IBean[] sortedBeans = beans.toArray(new IBean[beans.size()]);
Arrays.sort(sortedBeans, new Comparator<IBean>() {
@Override
public int compare(IBean o1, IBean o2) {
return o1.getElementName().compareTo(o2.getElementName());
}
});
ITextSourceReference reference = bean.getNameLocation(true);
Set<String> names = new HashSet<String>();
String bName = bean.getElementName();
names.add(bName);
StringBuffer sb = new StringBuffer(bName);
for (IBean iBean : sortedBeans) {
if(!isAsYouTypeValidation()) {
getValidationContext().addLinkedCoreResource(SHORT_ID, name, iBean.getSourcePath(), true);
}
bName = iBean.getElementName();
if(bean!=iBean && !names.contains(bName)) {
names.add(bName);
sb.append(", ").append(bName);
}
}
addProblem(MessageFormat.format(CDIValidationMessages.DUPLCICATE_EL_NAME[getVersionIndex(bean)], sb.toString()), CDIPreferences.AMBIGUOUS_EL_NAMES, reference, bean.getResource());
} else {
/*
* • the EL name of one bean is of the form x.y, where y is a valid bean EL name, and x is the EL name of the other bean,
* the container automatically detects the problem and treats it as a deployment problem.
*/
if(name.indexOf('.')>0) {
StringTokenizer st = new StringTokenizer(name, ".", false);
StringBuffer xName = new StringBuffer();
while(st.hasMoreTokens()) {
if(xName.length()>0) {
xName.append('.');
}
xName.append(st.nextToken());
if(st.hasMoreTokens()) {
String xNameAsString = xName.toString();
Collection<IBean> xBeans = context.getCdiProject().getBeans(xNameAsString, true);
if(!xBeans.isEmpty()) {
String yName = name.substring(xNameAsString.length()+1);
IStatus status = JavaConventions.validateJavaTypeName(yName, CompilerOptions.VERSION_1_6, CompilerOptions.VERSION_1_6);
if (status.getSeverity() != IStatus.ERROR) {
ITextSourceReference reference = bean.getNameLocation(true);
if(reference==null) {
reference = CDIUtil.getNamedDeclaration(bean);
}
addProblem(MessageFormat.format(CDIValidationMessages.UNRESOLVABLE_EL_NAME[getVersionIndex(bean)], name, yName, xNameAsString, xBeans.iterator().next().getElementName()), CDIPreferences.AMBIGUOUS_EL_NAMES, reference, bean.getResource());
break;
}
}
}
}
}
}
}
}
/*
* (non-Javadoc)
* @see org.jboss.tools.jst.web.kb.internal.validation.ValidationErrorManager#shouldCheckDuplicateMarkers()
*/
@Override
protected boolean shouldCheckDuplicateMarkers() {
return true;
}
/*
* Returns set of EL names which are declared in the resource
*/
private Set<String> getELNamesByResource(CDIValidationContext context, IPath resourcePath) {
Collection<IBean> beans = context.getCdiProject().getBeans(resourcePath);
if(beans.isEmpty()) {
return Collections.emptySet();
}
Set<IBeanKeyProvider> ps = context.getCdiProject().getNature().getExtensionManager().getFeatures(IBeanKeyProvider.class);
Set<String> result = new HashSet<String>();
for (IBean bean : beans) {
String name = bean.getName();
if(name!=null) {
result.add(name);
}
for (IBeanKeyProvider p: ps) {
String key = p.getKey(bean);
if(key != null) {
result.add(key);
}
}
}
return result;
}
private IType getTypeOfInjection(IInjectionPoint injection) {
IParametedType parametedType = injection.getType();
return parametedType==null?null:parametedType.getType();
}
private void addLinkedStereotypes(String beanPath, IStereotyped stereotyped) {
if(!isAsYouTypeValidation()) {
for (IStereotypeDeclaration stereotypeDeclaration : stereotyped.getStereotypeDeclarations()) {
IStereotype stereotype = stereotypeDeclaration.getStereotype();
if (stereotype != null && shouldValidateType(stereotype.getSourceType())) {
getValidationContext().addLinkedCoreResource(SHORT_ID, beanPath, stereotype.getSourcePath(), false);
}
}
}
}
private void addLinkedInterceptorBindings(String beanPath, IInterceptorBinded binded) {
if(!isAsYouTypeValidation()) {
for (IInterceptorBindingDeclaration bindingDeclaration : CDIUtil.getAllInterceptorBindingDeclaratios(binded)) {
IInterceptorBinding binding = bindingDeclaration.getInterceptorBinding();
if (binding != null && shouldValidateType(binding.getSourceType())) {
getValidationContext().addLinkedCoreResource(SHORT_ID, beanPath, binding.getSourcePath(), false);
}
}
}
}
private void validateClassBean(IClassBean bean) {
validateInitializers(bean);
validateDisposers(bean);
validateObserves(bean);
if (!(bean instanceof ISessionBean)) {
validateManagedBean(bean);
} else {
validateSessionBean((ISessionBean) bean);
}
validateMixedClassBean(bean);
validateConstructors(bean);
validateInterceptorBindings(bean);
}
private void validateInterceptorBindings(IClassBean bean) {
/*
* 9.5.2. Interceptor binding types with members
* - the set of interceptor bindings of a bean or interceptor, including bindings
* inherited from stereotypes and other interceptor bindings, has two instances
* of a certain interceptor binding type and the instances have different values
* of some annotation member
*/
try {
if(hasConflictedInterceptorBindings(bean)) {
//TODO consider putting markers to interceptor bindings/stereotype declarations.
ITextSourceReference reference = CDIUtil.convertToSourceReference(bean.getBeanClass().getNameRange(), bean.getResource(), bean.getBeanClass());
addProblem(CDIValidationMessages.CONFLICTING_INTERCEPTOR_BINDINGS[getVersionIndex(bean)], CDIPreferences.CONFLICTING_INTERCEPTOR_BINDINGS, reference, bean.getResource());
}
for (IBeanMethod method : bean.getAllMethods()) {
if(hasConflictedInterceptorBindings(method)) {
//TODO consider putting markers to interceptor bindings/stereotype declarations.
ITextSourceReference reference = CDIUtil.convertToSourceReference(method.getMethod().getNameRange(), bean.getResource(), method.getMethod());
addProblem(CDIValidationMessages.CONFLICTING_INTERCEPTOR_BINDINGS[getVersionIndex(bean)], CDIPreferences.CONFLICTING_INTERCEPTOR_BINDINGS, reference, bean.getResource());
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
} catch (CoreException e) {
CDICorePlugin.getDefault().logError(e);
}
}
private boolean hasConflictedInterceptorBindings(IInterceptorBinded binded) throws CoreException {
Collection<IInterceptorBindingDeclaration> declarations = CDIUtil.getAllInterceptorBindingDeclaratios(binded);
if(declarations.size()>1) {
Map<String, String> keys = new HashMap<String, String>();
for (IInterceptorBindingDeclaration declaration : declarations) {
IType type = declaration.getInterceptorBinding().getSourceType();
if(type!=null) {
String name = type.getFullyQualifiedName();
String key = CDIProject.getAnnotationDeclarationKey(declaration);
String anotherKey = keys.get(name);
if(anotherKey!=null) {
if(!anotherKey.equals(key)) {
return true;
}
} else {
keys.put(name, key);
}
}
}
}
return false;
}
private void validateSpecializingBean(IBean bean) {
/*
* 4.3.1. Direct and indirect specialization
* - decorator or interceptor is annotated @Specializes (Non-Portable behavior)
*/
IAnnotationDeclaration specializesDeclaration = bean.getSpecializesAnnotationDeclaration();
if(specializesDeclaration!=null) {
if(bean instanceof IDecorator) {
addProblem(CDIValidationMessages.DECORATOR_ANNOTATED_SPECIALIZES[getVersionIndex(bean)], CDIPreferences.INTERCEPTOR_ANNOTATED_SPECIALIZES, specializesDeclaration, bean.getResource(), DECORATOR_ANNOTATED_SPECIALIZES_ID);
} else if(bean instanceof IInterceptor) {
addProblem(CDIValidationMessages.INTERCEPTOR_ANNOTATED_SPECIALIZES[getVersionIndex(bean)], CDIPreferences.INTERCEPTOR_ANNOTATED_SPECIALIZES, specializesDeclaration, bean.getResource(), INTERCEPTOR_ANNOTATED_SPECIALIZES_ID);
}
}
IBean specializedBean = bean.getSpecializedBean();
if(specializedBean!=null) {
if(!isAsYouTypeValidation() && shouldValidateType(specializedBean.getBeanClass())) {
getValidationContext().addLinkedCoreResource(SHORT_ID, bean.getSourcePath().toString(), specializedBean.getSourcePath(), false);
}
String beanClassName = bean.getBeanClass().getElementName();
String beanName = bean instanceof IBeanMethod?beanClassName + "." + ((IBeanMethod)bean).getSourceMember().getElementName() + "()":beanClassName;
String specializingBeanClassName = specializedBean.getBeanClass().getElementName();
String specializingBeanName = specializedBean instanceof IBeanMethod?specializingBeanClassName + "." + ((IBeanMethod)specializedBean).getSourceMember().getElementName() + "()":specializingBeanClassName;
/*
* 4.3.1. Direct and indirect specialization
* - X specializes Y but does not have some bean type of Y
*/
Set<String> legalTypes = new HashSet<String>();
for (IParametedType type : bean.getLegalTypes()) {
if(type.getType() != null) legalTypes.add(type.getType().getFullyQualifiedName());
}
Set<String> missingTypesSet = new TreeSet<String>();
for (IParametedType specializingType : specializedBean.getLegalTypes()) {
if(!legalTypes.contains(specializingType.getType().getFullyQualifiedName())) {
missingTypesSet.add(specializingType.getType().getElementName());
}
}
StringBuffer missingTypes = new StringBuffer();
for (String type: missingTypesSet) {
if(missingTypes.length() > 0) {
missingTypes.append(", ");
}
missingTypes.append(type);
}
if(missingTypes.length()>0) {
addProblem(CDIValidationMessages.MISSING_TYPE_IN_SPECIALIZING_BEAN[getVersionIndex(bean)], CDIPreferences.MISSING_TYPE_IN_SPECIALIZING_BEAN,
new String[]{beanName, specializingBeanName, missingTypes.toString()},
bean.getSpecializesAnnotationDeclaration(), bean.getResource());
}
/*
* 4.3.1. Direct and indirect specialization
* - X specializes Y and Y has a name and X declares a name explicitly, using @Named
*/
if(specializedBean.getName()!=null) {
IAnnotationDeclaration nameDeclaration = bean.getAnnotation(CDIConstants.NAMED_QUALIFIER_TYPE_NAME);
if(nameDeclaration!=null) {
addProblem(CDIValidationMessages.CONFLICTING_NAME_IN_SPECIALIZING_BEAN[getVersionIndex(specializedBean)], CDIPreferences.CONFLICTING_NAME_IN_SPECIALIZING_BEAN,
new String[]{beanName, specializingBeanName},
nameDeclaration, bean.getResource());
}
}
/*
* 5.1.3. Inconsistent specialization
* - Suppose an enabled bean X specializes a second bean Y. If there is another enabled bean that specializes Y we say that inconsistent
* specialization exists. The container automatically detects inconsistent specialization and treats it as a deployment problem.
*/
if(bean.isEnabled() && specializedBean instanceof IClassBean) {
IClassBean supperClassBean = (IClassBean)specializedBean;
Collection<? extends IClassBean> allSpecializingBeans = supperClassBean.getSpecializingBeans();
if(allSpecializingBeans.size()>1) {
Set<String> specializingBeanNames = new TreeSet<String>();
for (IClassBean specializingBean : allSpecializingBeans) {
if(specializingBean != bean && specializingBean.isEnabled()) {
specializingBeanNames.add(specializingBean.getElementName());
if(!isAsYouTypeValidation() && shouldValidateType(specializingBean.getBeanClass())) {
getValidationContext().addLinkedCoreResource(SHORT_ID, specializingBean.getSourcePath().toString(), bean.getSourcePath(), false);
getValidationContext().addLinkedCoreResource(SHORT_ID, bean.getSourcePath().toString(), specializingBean.getSourcePath(), false);
}
}
}
if(!specializingBeanNames.isEmpty() && specializesDeclaration!=null) {
StringBuffer sb = new StringBuffer(bean.getElementName());
for (String name: specializingBeanNames) {
sb.append(", ").append(name);
}
addProblem(CDIValidationMessages.INCONSISTENT_SPECIALIZATION[getVersionIndex(bean)], CDIPreferences.INCONSISTENT_SPECIALIZATION,
new String[]{sb.toString(), supperClassBean.getElementName()},
specializesDeclaration, bean.getResource());
}
}
}
}
}
private void validateConstructors(IClassBean bean) {
Collection<IBeanMethod> constructors = bean.getBeanConstructors();
if(constructors.size()>1) {
Collection<IAnnotationDeclaration> injects = new ArrayList<IAnnotationDeclaration>();
for (IBeanMethod constructor : constructors) {
IAnnotationDeclaration inject = constructor.getAnnotation(CDIConstants.INJECT_ANNOTATION_TYPE_NAME);
if(inject!=null) {
injects.add(inject);
}
}
/*
* 3.7.1. Declaring a bean constructor
* - bean class has more than one constructor annotated @Inject
*/
if(injects.size()>1) {
for (IAnnotationDeclaration inject : injects) {
addProblem(CDIValidationMessages.MULTIPLE_INJECTION_CONSTRUCTORS[getVersionIndex(bean)], CDIPreferences.MULTIPLE_INJECTION_CONSTRUCTORS, inject, bean.getResource(), MULTIPLE_INJECTION_CONSTRUCTORS_ID);
}
}
}
}
int getVersionIndex(ICDIElement element) {
return element.getCDIProject().getVersion().getIndex();
}
private void validateObserves(IClassBean bean) {
Collection<IBeanMethod> observes = bean.getAllMethods();
if (observes.isEmpty()) {
return;
}
for (IBeanMethod observer : observes) {
if(!observer.isObserver()) {
continue;
}
List<IParameter> params = observer.getParameters();
Collection<ITextSourceReference> declarations = new ArrayList<ITextSourceReference>();
for (IParameter param : params) {
ITextSourceReference declaration = param.getAnnotationPosition(CDIConstants.OBSERVERS_ANNOTATION_TYPE_NAME);
if (declaration != null) {
declarations.add(declaration);
/*
* 10.4.2. Declaring an observer method
* - bean with scope @Dependent has an observer method declared notifyObserver=IF_EXISTS
*/
if(bean.getScope()!=null && CDIConstants.DEPENDENT_ANNOTATION_TYPE_NAME.equals(bean.getScope().getSourceType().getFullyQualifiedName())) {
ICompilationUnit unit = observer.getMethod().getCompilationUnit();
if(unit!=null) {
try {
String source = unit.getSource();
ISourceRange unitRange = unit.getSourceRange();
int start = declaration.getStartPosition() - unitRange.getOffset();
int end = start + declaration.getLength();
int position = source.substring(start, end).indexOf("IF_EXISTS");
// TODO Shecks if IF_EXISTS as a string. But this string may be in a comment then we will show incorrect error message.
if(position>11) {
addProblem(CDIValidationMessages.ILLEGAL_CONDITIONAL_OBSERVER[getVersionIndex(bean)], CDIPreferences.ILLEGAL_CONDITIONAL_OBSERVER, declaration, bean.getResource());
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
}
}
}
/*
* 10.4.2. Declaring an observer method
* - method has more than one parameter annotated @Observes
*/
if(declarations.size()>1) {
for (ITextSourceReference declaration : declarations) {
addProblem(CDIValidationMessages.MULTIPLE_OBSERVING_PARAMETERS[getVersionIndex(bean)], CDIPreferences.MULTIPLE_OBSERVING_PARAMETERS, declaration, bean.getResource(), MULTIPLE_OBSERVING_PARAMETERS_ID);
}
}
/*
* 3.7.1. Declaring a bean constructor
* - bean constructor has a parameter annotated @Observes
*
* 10.4.2. Declaring an observer method
* - observer method is annotated @Inject
*/
IAnnotationDeclaration injectDeclaration = observer.getAnnotation(CDIConstants.INJECT_ANNOTATION_TYPE_NAME);
try {
if (injectDeclaration != null) {
String pref = observer.getMethod().isConstructor()?CDIPreferences.CONSTRUCTOR_PARAMETER_ILLEGALLY_ANNOTATED:CDIPreferences.OBSERVER_ANNOTATED_INJECT;
String message = observer.getMethod().isConstructor()?CDIValidationMessages.CONSTRUCTOR_PARAMETER_ANNOTATED_OBSERVES[getVersionIndex(observer)]:CDIValidationMessages.OBSERVER_ANNOTATED_INJECT[getVersionIndex(observer)];
int messageId = observer.getMethod().isConstructor()?CONSTRUCTOR_PARAMETER_ANNOTATED_OBSERVES_ID:OBSERVER_ANNOTATED_INJECT_ID;
addProblem(message, pref, injectDeclaration, bean.getResource(), messageId);
for (ITextSourceReference declaration : declarations) {
addProblem(message, pref, declaration, bean.getResource(), messageId);
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
/*
* 10.4.2. Declaring an observer method
* - interceptor or decorator has a method with a parameter annotated @Observes
*/
if(bean instanceof IDecorator) {
for (ITextSourceReference declaration : declarations) {
addProblem(CDIValidationMessages.OBSERVER_IN_DECORATOR[getVersionIndex(bean)], CDIPreferences.OBSERVER_IN_INTERCEPTOR_OR_DECORATOR, declaration, bean.getResource(), OBSERVER_IN_DECORATOR_ID);
}
} else if(bean instanceof IInterceptor) {
for (ITextSourceReference declaration : declarations) {
addProblem(CDIValidationMessages.OBSERVER_IN_INTERCEPTOR[getVersionIndex(bean)], CDIPreferences.OBSERVER_IN_INTERCEPTOR_OR_DECORATOR, declaration, bean.getResource(), OBSERVER_IN_INTERCEPTOR_ID);
}
}
validateSessionBeanMethod(bean, observer, declarations, CDIValidationMessages.ILLEGAL_OBSERVER_IN_SESSION_BEAN[getVersionIndex(bean)], CDIPreferences.ILLEGAL_OBSERVER_IN_SESSION_BEAN, ILLEGAL_OBSERVER_IN_SESSION_BEAN_ID);
}
}
private void validateDisposers(IClassBean bean) {
Collection<IBeanMethod> disposers = bean.getDisposers();
if (disposers.isEmpty()) {
return;
}
Set<IBeanMethod> boundDisposers = new HashSet<IBeanMethod>();
for (IProducer producer : bean.getProducers()) {
if(producer.exists() && (producer instanceof IProducerMethod || producer.getCDIProject().getVersion() != CDIVersion.CDI_1_0)) {
Collection<IBeanMethod> disposerMethods = producer.getCDIProject().resolveDisposers(producer);
boundDisposers.addAll(disposerMethods);
if (disposerMethods.size() > 1) {
/*
* 3.3.7. Disposer method resolution (CDI 1.0)
* - there are multiple disposer methods for a single producer method
* 3.5.3. Disposer method resolution (CDI 1.1 and 1.2)
* - there are multiple disposer methods for a single producer method or producer field
*/
for (IBeanMethod disposerMethod : disposerMethods) {
Collection<ITextSourceReference> disposerDeclarations = CDIUtil.getAnnotationPossitions(disposerMethod, CDIConstants.DISPOSES_ANNOTATION_TYPE_NAME);
for (ITextSourceReference declaration : disposerDeclarations) {
addProblem(CDIValidationMessages.MULTIPLE_DISPOSERS_FOR_PRODUCER[getVersionIndex(bean)], CDIPreferences.MULTIPLE_DISPOSERS_FOR_PRODUCER, declaration, bean.getResource(), MULTIPLE_DISPOSERS_FOR_PRODUCER_ID);
}
}
}
}
}
for (IBeanMethod disposer : disposers) {
if(!disposer.exists()) {
continue;
}
List<IParameter> params = disposer.getParameters();
/*
* 3.3.6. Declaring a disposer method
* - method has more than one parameter annotated @Disposes
*/
Collection<ITextSourceReference> disposerDeclarations = new ArrayList<ITextSourceReference>();
for (IParameter param : params) {
ITextSourceReference declaration = param.getAnnotationPosition(CDIConstants.DISPOSES_ANNOTATION_TYPE_NAME);
if (declaration != null && param.exists()) {
disposerDeclarations.add(declaration);
}
}
if (disposerDeclarations.size() > 1) {
for (ITextSourceReference declaration : disposerDeclarations) {
addProblem(CDIValidationMessages.MULTIPLE_DISPOSING_PARAMETERS[getVersionIndex(disposer)], CDIPreferences.MULTIPLE_DISPOSING_PARAMETERS, declaration, bean.getResource(), MULTIPLE_DISPOSING_PARAMETERS_ID);
}
}
/*
* 3.3.6. Declaring a disposer method
* - a disposer method has a parameter annotated @Observes.
*
* 10.4.2. Declaring an observer method
* - a observer method has a parameter annotated @Disposes.
*/
Collection<ITextSourceReference> declarations = new ArrayList<ITextSourceReference>();
boolean observesExists = false;
declarations.addAll(disposerDeclarations);
for (IParameter param : params) {
ITextSourceReference declaration = param.getAnnotationPosition(CDIConstants.OBSERVERS_ANNOTATION_TYPE_NAME);
if (declaration != null && param.exists()) {
declarations.add(declaration);
observesExists = true;
}
}
if (observesExists) {
for (ITextSourceReference declaration : declarations) {
addProblem(CDIValidationMessages.OBSERVER_PARAMETER_ILLEGALLY_ANNOTATED[getVersionIndex(disposer)], CDIPreferences.OBSERVER_PARAMETER_ILLEGALLY_ANNOTATED, declaration, bean.getResource(), OBSERVER_PARAMETER_ILLEGALLY_ANNOTATED_ID);
}
}
/*
* 3.3.6. Declaring a disposer method
* - a disposer method is annotated @Inject.
*
* 3.9.1. Declaring an initializer method
* - an initializer method has a parameter annotated @Disposes
*
* 3.7.1. Declaring a bean constructor
* - bean constructor has a parameter annotated @Disposes
*/
IAnnotationDeclaration injectDeclaration = disposer.getAnnotation(CDIConstants.INJECT_ANNOTATION_TYPE_NAME);
try {
if (injectDeclaration != null) {
String pref = disposer.getMethod().isConstructor()?CDIPreferences.CONSTRUCTOR_PARAMETER_ILLEGALLY_ANNOTATED:CDIPreferences.DISPOSER_ANNOTATED_INJECT;
String message = disposer.getMethod().isConstructor()?CDIValidationMessages.CONSTRUCTOR_PARAMETER_ANNOTATED_DISPOSES[getVersionIndex(disposer)]:CDIValidationMessages.DISPOSER_ANNOTATED_INJECT[getVersionIndex(disposer)];
int messageId = disposer.getMethod().isConstructor()?CONSTRUCTOR_PARAMETER_ANNOTATED_DISPOSES_ID:DISPOSER_ANNOTATED_INJECT_ID;
addProblem(message, pref, injectDeclaration, bean.getResource(), messageId);
for (ITextSourceReference declaration : disposerDeclarations) {
addProblem(message, pref, declaration, bean.getResource(), messageId);
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
/*
* 3.3.6. Declaring a disposer method
* - a non-static method of a session bean class has a parameter annotated @Disposes, and the method is not a business method of the session bean
*/
validateSessionBeanMethod(bean, disposer, disposerDeclarations, CDIValidationMessages.ILLEGAL_DISPOSER_IN_SESSION_BEAN[getVersionIndex(bean)],
CDIPreferences.ILLEGAL_DISPOSER_IN_SESSION_BEAN, ILLEGAL_DISPOSER_IN_SESSION_BEAN_ID);
/*
* 3.3.6. Declaring a disposer method
* - decorators may not declare disposer methods
*/
if (bean instanceof IDecorator) {
IDecorator decorator = (IDecorator) bean;
ITextSourceReference decoratorDeclaration = decorator.getDecoratorAnnotation();
if(decoratorDeclaration == null) {
//for custom implementations
decoratorDeclaration = decorator.getNameLocation(true);
}
addProblem(CDIValidationMessages.DISPOSER_IN_DECORATOR[getVersionIndex(bean)], CDIPreferences.DISPOSER_IN_INTERCEPTOR_OR_DECORATOR, decoratorDeclaration, bean.getResource(), DISPOSER_IN_DECORATOR_ID);
for (ITextSourceReference declaration : disposerDeclarations) {
addProblem(CDIValidationMessages.DISPOSER_IN_DECORATOR[getVersionIndex(bean)], CDIPreferences.DISPOSER_IN_INTERCEPTOR_OR_DECORATOR, declaration, bean.getResource(), DISPOSER_IN_DECORATOR_ID);
}
}
/*
* 3.3.6. Declaring a disposer method
* - interceptors may not declare disposer methods
*/
if (bean instanceof IInterceptor) {
IInterceptor interceptor = (IInterceptor) bean;
ITextSourceReference interceptorDeclaration = interceptor.getInterceptorAnnotation();
if(interceptorDeclaration == null) {
//for custom implementations
interceptorDeclaration = interceptor.getNameLocation(true);
}
addProblem(CDIValidationMessages.DISPOSER_IN_INTERCEPTOR[getVersionIndex(bean)], CDIPreferences.DISPOSER_IN_INTERCEPTOR_OR_DECORATOR, interceptorDeclaration, bean
.getResource(), DISPOSER_IN_INTERCEPTOR_ID);
for (ITextSourceReference declaration : disposerDeclarations) {
addProblem(CDIValidationMessages.DISPOSER_IN_INTERCEPTOR[getVersionIndex(bean)], CDIPreferences.DISPOSER_IN_INTERCEPTOR_OR_DECORATOR, declaration, bean
.getResource(), DISPOSER_IN_INTERCEPTOR_ID);
}
}
/*
* 3.3.7. Disposer method resolution
* - there is no producer method declared by the (same) bean class that is assignable to the disposed parameter of a disposer method
* 3.5.3. Disposer method resolution (CDI 1.1 and 1.2)
* - there is no producer method or producer field declared by the bean class that is assignable to the disposed parameter of a disposer method
*/
if (!boundDisposers.contains(disposer)) {
for (ITextSourceReference declaration : disposerDeclarations) {
addProblem(CDIValidationMessages.NO_PRODUCER_MATCHING_DISPOSER[getVersionIndex(disposer)], CDIPreferences.NO_PRODUCER_MATCHING_DISPOSER, declaration, bean.getResource());
}
}
}
}
/**
* If the method is not a static method and is not a business method of the
* session bean and is observer or disposer then mark it as incorrect.
*
* @param bean
* @param method
* @param annotatedParams
* @param errorKey
*/
private void validateSessionBeanMethod(IClassBean bean, IBeanMethod method, Collection<ITextSourceReference> annotatedParams, String errorMessage, String preferencesKey, int id) {
if (bean instanceof ISessionBean && annotatedParams != null) {
IMethod iMethod = CDIUtil.getBusinessMethodDeclaration((SessionBean)bean, method);
if(iMethod==null) {
saveAllSuperTypesAsLinkedResources(bean);
for (ITextSourceReference declaration : annotatedParams) {
String bindedErrorMessage = NLS.bind(errorMessage, new String[]{method.getMethod().getElementName(), bean.getBeanClass().getElementName()});
addProblem(bindedErrorMessage, preferencesKey, declaration, bean.getResource(), id);
}
} else if (!isAsYouTypeValidation() && iMethod != method.getMethod() && !iMethod.isBinary()) {
getValidationContext().addLinkedCoreResource(SHORT_ID, bean.getSourcePath().toString(), iMethod.getResource().getFullPath(), false);
}
}
}
private static final String[] RESOURCE_ANNOTATIONS = { CDIConstants.RESOURCE_ANNOTATION_TYPE_NAME, CDIConstants.WEB_SERVICE_REF_ANNOTATION_TYPE_NAME, CDIConstants.EJB_ANNOTATION_TYPE_NAME, CDIConstants.PERSISTENCE_CONTEXT_ANNOTATION_TYPE_NAME, CDIConstants.PERSISTENCE_UNIT_ANNOTATION_TYPE_NAME };
private void validateProducer(CDIValidationContext context, IProducer producer) {
try {
Collection<ITypeDeclaration> typeDeclarations = producer.getAllTypeDeclarations();
String[] typeVariables = producer.getBeanClass().getTypeParameterSignatures();
ITypeDeclaration typeDeclaration = null;
ITextSourceReference typeDeclarationReference = null;
if (!typeDeclarations.isEmpty()) {
/*
* 3.3. Producer methods
* - producer method return type contains a wildcard type parameter
*
* 2.2.1 Legal bean types
* - a parameterized type that contains a wildcard type parameter is not a legal bean type.
* - in CDI 1.2 an array type, whose component type is not a legal bean type, is not a legal bean type.
*
* 3.4. Producer fields
* - producer field type contains a wildcard type parameter
*/
typeDeclaration = typeDeclarations.iterator().next();
typeDeclarationReference = CDIUtil.convertToJavaSourceReference(typeDeclaration, producer.getSourceMember());
String[] paramTypes = Signature.getTypeArguments(typeDeclaration.getSignature());
boolean variable = false;
for (String paramType : paramTypes) {
if (Signature.getTypeSignatureKind(paramType) == Signature.WILDCARD_TYPE_SIGNATURE) {
if (producer instanceof IProducerField) {
addProblem(CDIValidationMessages.PRODUCER_FIELD_TYPE_HAS_WILDCARD[getVersionIndex(producer)], CDIPreferences.PRODUCER_METHOD_RETURN_TYPE_HAS_WILDCARD_OR_VARIABLE, typeDeclarationReference,
producer.getResource());
} else {
addProblem(CDIValidationMessages.PRODUCER_METHOD_RETURN_TYPE_HAS_WILDCARD[getVersionIndex(producer)], CDIPreferences.PRODUCER_METHOD_RETURN_TYPE_HAS_WILDCARD_OR_VARIABLE,
typeDeclarationReference, producer.getResource());
}
} else if(!variable && isTypeVariable(producer, Signature.toString(paramType), typeVariables)) {
/*
* 3.3. Producer methods
* - producer method with a parameterized return type with a type variable declares any scope other than @Dependent
*
* 3.4. Producer fields
* - producer field with a parameterized type with a type variable declares any scope other than @Dependent
*/
variable = true;
IAnnotationDeclaration scopeOrStereotypeDeclaration = CDIUtil.getDifferentScopeDeclarationThanDepentend(producer);
if (scopeOrStereotypeDeclaration != null) {
boolean field = producer instanceof IProducerField;
addProblem(field ? CDIValidationMessages.ILLEGAL_SCOPE_FOR_PRODUCER_FIELD[getVersionIndex(producer)] : CDIValidationMessages.ILLEGAL_SCOPE_FOR_PRODUCER_METHOD[getVersionIndex(producer)],
field ? CDIPreferences.ILLEGAL_SCOPE_FOR_BEAN : CDIPreferences.ILLEGAL_SCOPE_FOR_BEAN,
scopeOrStereotypeDeclaration, producer.getResource());
}
break;
}
}
}
/*
* 3.3.2. Declaring a producer method
* - producer method is annotated @Inject
*/
IAnnotationDeclaration inject = producer.getAnnotation(CDIConstants.INJECT_ANNOTATION_TYPE_NAME);
if (inject != null) {
addProblem(CDIValidationMessages.PRODUCER_ANNOTATED_INJECT[getVersionIndex(producer)], CDIPreferences.PRODUCER_ANNOTATED_INJECT, inject, inject.getResource() != null ? inject.getResource() : producer.getResource(), PRODUCER_ANNOTATED_INJECT_ID);
}
if (producer instanceof IProducerField) {
/*
* 3.5.1. Declaring a resource
* - producer field declaration specifies an EL name (together with one of @Resource, @PersistenceContext, @PersistenceUnit, @EJB, @WebServiceRef)
*/
IProducerField producerField = (IProducerField) producer;
if (producerField.getName() != null) {
IAnnotationDeclaration declaration;
for (String annotationType : RESOURCE_ANNOTATIONS) {
declaration = producerField.getAnnotation(annotationType);
if (declaration != null) {
IAnnotationDeclaration nameDeclaration = producerField.getAnnotation(CDIConstants.NAMED_QUALIFIER_TYPE_NAME);
if (nameDeclaration != null) {
declaration = nameDeclaration;
}
addProblem(CDIValidationMessages.RESOURCE_PRODUCER_FIELD_SETS_EL_NAME[getVersionIndex(producer)], CDIPreferences.RESOURCE_PRODUCER_FIELD_SETS_EL_NAME, declaration, producer.getResource());
}
}
}
/*
* 3.4. Producer fields
* - producer field type is a type variable
*/
if (typeVariables.length > 0) {
String typeSign = producerField.getField().getTypeSignature();
String typeString = Signature.toString(typeSign);
if(isTypeVariable(producerField, typeString, typeVariables)) {
addProblem(CDIValidationMessages.PRODUCER_FIELD_TYPE_IS_VARIABLE[getVersionIndex(producer)], CDIPreferences.PRODUCER_METHOD_RETURN_TYPE_HAS_WILDCARD_OR_VARIABLE, typeDeclaration != null ? typeDeclarationReference : producer, producer.getResource());
}
}
/*
* 3.4.2. Declaring a producer field
* - non-static field of a session bean class is annotated @Produces
*/
if(producer.getClassBean() instanceof ISessionBean && !Flags.isStatic(producerField.getField().getFlags())) {
addProblem(CDIValidationMessages.ILLEGAL_PRODUCER_FIELD_IN_SESSION_BEAN[getVersionIndex(producer)], CDIPreferences.ILLEGAL_PRODUCER_METHOD_IN_SESSION_BEAN, producer.getProducesAnnotation(), producer.getResource(), ILLEGAL_PRODUCER_FIELD_IN_SESSION_BEAN_ID);
}
} else {
IProducerMethod producerMethod = (IProducerMethod) producer;
List<IParameter> params = producerMethod.getParameters();
Collection<ITextSourceReference> observesDeclarations = new ArrayList<ITextSourceReference>();
Collection<ITextSourceReference> disposalDeclarations = new ArrayList<ITextSourceReference>();
IAnnotationDeclaration producesDeclaration = producerMethod.getAnnotation(CDIConstants.PRODUCES_ANNOTATION_TYPE_NAME);
if(producesDeclaration != null) {
observesDeclarations.add(producesDeclaration);
disposalDeclarations.add(producesDeclaration);
}
for (IParameter param : params) {
/*
* 3.3.6. Declaring a disposer method
* - a disposer method is annotated @Produces.
*
* 3.3.2. Declaring a producer method
* - a has a parameter annotated @Disposes
*/
ITextSourceReference declaration = param.getAnnotationPosition(CDIConstants.DISPOSES_ANNOTATION_TYPE_NAME);
if (declaration != null) {
disposalDeclarations.add(declaration);
}
/*
* 3.3.2. Declaring a producer method
* - a has a parameter annotated @Observers
*
* 10.4.2. Declaring an observer method
* - an observer method is annotated @Produces
*/
declaration = param.getAnnotationPosition(CDIConstants.OBSERVERS_ANNOTATION_TYPE_NAME);
if (declaration != null) {
observesDeclarations.add(declaration);
}
}
if (observesDeclarations.size() > 1) {
for (ITextSourceReference declaration : observesDeclarations) {
addProblem(CDIValidationMessages.PRODUCER_PARAMETER_ILLEGALLY_ANNOTATED_OBSERVES[getVersionIndex(producer)], CDIPreferences.PRODUCER_PARAMETER_ILLEGALLY_ANNOTATED,
declaration, producer.getResource(), PRODUCER_PARAMETER_ILLEGALLY_ANNOTATED_OBSERVES_ID);
}
}
if (disposalDeclarations.size() > 1) {
for (ITextSourceReference declaration : disposalDeclarations) {
addProblem(CDIValidationMessages.PRODUCER_PARAMETER_ILLEGALLY_ANNOTATED_DISPOSES[getVersionIndex(producer)], CDIPreferences.PRODUCER_PARAMETER_ILLEGALLY_ANNOTATED,
declaration, producer.getResource(), PRODUCER_PARAMETER_ILLEGALLY_ANNOTATED_DISPOSES_ID);
}
}
/*
* 3.3. Producer methods
* - producer method return type is a type variable
*
* 2.2.1 - Legal bean types
* - a type variable is not a legal bean type
* - in CDI 1.2 an array type, whose component type is not a legal bean type, is not a legal bean type.
*/
String typeSign = producerMethod.getMethod().getReturnType();
String typeString = Signature.toString(typeSign);
if(isTypeVariable(producerMethod, typeString, typeVariables)) {
addProblem(CDIValidationMessages.PRODUCER_METHOD_RETURN_TYPE_IS_VARIABLE[getVersionIndex(producer)], CDIPreferences.PRODUCER_METHOD_RETURN_TYPE_HAS_WILDCARD_OR_VARIABLE,
typeDeclaration != null ? typeDeclarationReference : producer, producer.getResource());
}
/*
* 3.3.2. Declaring a producer method
* - non-static method of a session bean class is annotated @Produces, and the method is not a business method of the session bean
*/
IClassBean classBean = producer.getClassBean();
if(classBean instanceof ISessionBean) {
IMethod method = CDIUtil.getBusinessMethodDeclaration((SessionBean)classBean, producerMethod);
if(method==null) {
String bindedErrorMessage = NLS.bind(CDIValidationMessages.ILLEGAL_PRODUCER_METHOD_IN_SESSION_BEAN[getVersionIndex(producer)], new String[]{producerMethod.getMethod().getElementName(), producer.getBeanClass().getElementName()});
addProblem(bindedErrorMessage, CDIPreferences.ILLEGAL_PRODUCER_METHOD_IN_SESSION_BEAN, producer.getProducesAnnotation(), producer.getResource(), ILLEGAL_PRODUCER_METHOD_IN_SESSION_BEAN_ID);
saveAllSuperTypesAsLinkedResources(classBean);
} else if (!isAsYouTypeValidation() && method != producerMethod.getMethod() && method.exists() && !method.isReadOnly()) {
getValidationContext().addLinkedCoreResource(SHORT_ID, classBean.getSourcePath().toString(), method.getResource().getFullPath(), false);
}
}
IAnnotationDeclaration sDeclaration = producerMethod.getSpecializesAnnotationDeclaration();
if(sDeclaration!=null) {
if(Flags.isStatic(producerMethod.getMethod().getFlags())) {
/*
* 3.3.3. Specializing a producer method
* - method annotated @Specializes is static
*/
addProblem(CDIValidationMessages.ILLEGAL_SPECIALIZING_PRODUCER_STATIC[getVersionIndex(producer)], CDIPreferences.ILLEGAL_SPECIALIZING_BEAN, sDeclaration, producer.getResource());
} else {
/*
* 3.3.3. Specializing a producer method
* - method annotated @Specializes does not directly override another producer method
*/
IMethod superMethod = CDIUtil.getDirectOverridingMethodDeclaration(producerMethod);
boolean overrides = false;
if(superMethod!=null) {
IType superType = superMethod.getDeclaringType();
if(superType.isBinary()) {
IAnnotation[] ants = superMethod.getAnnotations();
for (IAnnotation an : ants) {
if(CDIConstants.PRODUCES_ANNOTATION_TYPE_NAME.equals(an.getElementName())) {
overrides = true;
}
}
} else {
Collection<IBean> beans = context.getCdiProject().getBeans(superType.getResource().getFullPath());
for (IBean iBean : beans) {
if(iBean instanceof IProducerMethod) {
IProducerMethod prMethod = (IProducerMethod)iBean;
if(prMethod.getMethod().isSimilar(superMethod)) {
overrides = true;
}
}
}
}
}
if(!overrides) {
addProblem(CDIValidationMessages.ILLEGAL_SPECIALIZING_PRODUCER_OVERRIDE[getVersionIndex(producer)], CDIPreferences.ILLEGAL_SPECIALIZING_BEAN, sDeclaration, producer.getResource());
}
saveAllSuperTypesAsLinkedResources(producer.getClassBean());
}
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
private boolean isTypeVariable(IProducer producer, String type, String[] typeVariables) throws JavaModelException {
boolean checkArrayType = CDIVersion.CDI_1_2.equals(producer.getCDIProject().getVersion());
if(producer instanceof IProducerMethod) {
ITypeParameter[] paramTypes = ((IProducerMethod)producer).getMethod().getTypeParameters();
for (ITypeParameter param : paramTypes) {
String variableName = param.getElementName();
if (variableName.equals(type) || (checkArrayType && type.startsWith(variableName + "["))) {
return true;
}
}
}
if (typeVariables.length > 0) {
for (String variableSig : typeVariables) {
String variableName = Signature.getTypeVariable(variableSig);
if (type.equals(variableName) || (checkArrayType && type.startsWith(variableName + "["))) {
return true;
}
}
}
return false;
}
private void saveAllSuperTypesAsLinkedResources(IBean bean) {
if(!isAsYouTypeValidation()) {
for (IParametedType type : bean.getAllTypes()) {
IType superType = type.getType();
if(superType!=null && !superType.isBinary() && superType.getResource()!=null && superType!=bean.getBeanClass()) {
getValidationContext().addLinkedCoreResource(SHORT_ID, bean.getSourcePath().toString(), superType.getResource().getFullPath(), false);
}
}
}
}
private void collectAllRelatedInjections(IFile validatingResource, Set<IPath> relatedResources) {
if(!asYouTypeValidation) {
CDIValidationContext context = getCDIContext(validatingResource);
ICDIProject cdiProject = context.getCdiProject();
collectAllRelatedInjectionsForBean(validatingResource, relatedResources);
if("beans.xml".equals(validatingResource.getName().toLowerCase())) {
List<INodeReference> nodes = cdiProject.getAlternativeClasses();
collectAllRelatedInjectionsForNode(nodes, relatedResources);
nodes = cdiProject.getDecoratorClasses();
collectAllRelatedInjectionsForNode(nodes, relatedResources);
nodes = cdiProject.getInterceptorClasses();
collectAllRelatedInjectionsForNode(nodes, relatedResources);
Set<IPath> dd = getCDIContext(validatingResource).getDependencies().getDirectDependencies(validatingResource.getFullPath());
if(dd != null) {
relatedResources.addAll(dd);
}
}
}
}
private void collectAllRelatedResourcesFromPackageInfo(IFile validatingResource, Set<IPath> relatedResources) {
if("package-info.java".equals(validatingResource.getName())) {
// Save links between package-info.java and all the java files in the package (see https://issues.jboss.org/browse/JBIDE-13172)
try {
IResource[] members = validatingResource.getParent().members();
for (IResource member : members) {
if((member instanceof IFile) && validatingResource!=member && "java".equalsIgnoreCase(member.getFileExtension())) {
IFile file = (IFile)member;
relatedResources.add(file.getFullPath());
collectAllRealtedCoreResources(file, relatedResources);
}
}
} catch (CoreException e) {
CDICorePlugin.getDefault().logError(e);
}
}
}
private void collectAllRelatedInjectionsForNode(List<INodeReference> nodes, Set<IPath> relatedResources) {
try {
for (INodeReference node : nodes) {
String className = node.getValue();
IType type = EclipseJavaUtil.findType(beansXmlValidator.getJavaProject(node.getResource()), className);
if(type!=null && !type.isBinary()) {
IResource resource = type.getResource();
if(type!=null && resource instanceof IFile) {
collectAllRelatedInjectionsForBean((IFile)resource, relatedResources);
}
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
void collectAllRelatedInjectionsForBean(IFile validatingResource, Set<IPath> relatedResources) {
if(!asYouTypeValidation) {
CDIValidationContext context = getCDIContext(validatingResource);
ICDIProject cdiProject = context.getCdiProject();
Collection<IBean> beans = cdiProject.getBeans(validatingResource.getFullPath());
if(!beans.isEmpty()) {
for (IBean bean : beans) {
for (IParametedType type : bean.getAllTypes()) {
IType superType = type.getType();
if(superType!=null) {
collectAllRelatedInjectionsForType(cdiProject, superType, bean, relatedResources);
}
}
}
} else if(validatingResource.getName().toLowerCase().endsWith(".java")) {
ICompilationUnit unit = EclipseUtil.getCompilationUnit(validatingResource);
if(unit!=null) {
try {
IType[] types = unit.getAllTypes();
for (IType type : types) {
ParametedType parametedType = ((CDIProject)cdiProject).getNature().getTypeFactory().newParametedType(type);
Collection<IParametedType> allTypes = parametedType.getAllTypes();
for (IParametedType iParametedType : allTypes) {
IType t = iParametedType.getType();
if(t!=null) {
collectAllRelatedInjectionsForType(cdiProject, t, null, relatedResources);
}
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
}
}
}
private void collectAllRelatedInjectionsForType(ICDIProject cdiProject, IType type, IBean bean, Set<IPath> relatedResources) {
for (IInjectionPoint injection : cdiProject.getInjections(type.getFullyQualifiedName())) {
if(!injection.getClassBean().getBeanClass().isBinary() && injection.getClassBean()!=bean) {
relatedResources.add(injection.getSourcePath());
}
}
}
/**
* Checks if the injection point injects some bean from a CDI extension and should be ignored by the validator during lookup validation.
* @param typeOfInjectionPoint
* @param injection
* @return
*/
private boolean shouldIgnoreInjection(CDIValidationContext context, IType typeOfInjectionPoint, IInjectionPoint injection) {
for (IInjectionPointValidatorFeature feature : context.getInjectionValidationFeatures()) {
if(feature.shouldIgnoreInjection(typeOfInjectionPoint, injection)) {
return true;
}
}
return false;
}
private void validateInitializers(IClassBean bean) {
for (IInitializerMethod initializer: bean.getInitializers()) {
validateInitializerMethod(initializer);
}
}
private void validateInitializerMethod(IInitializerMethod initializer) {
IAnnotationDeclaration named = initializer.getAnnotation(CDIConstants.NAMED_QUALIFIER_TYPE_NAME);
if (named != null) {
boolean valueExists = named.getMemberValue(null) != null;
if (!valueExists) {
addProblem(CDIValidationMessages.PARAM_INJECTION_DECLARES_EMPTY_NAME[getVersionIndex(initializer)], CDIPreferences.PARAM_INJECTION_DECLARES_EMPTY_NAME, named, initializer.getResource(), PARAM_INJECTION_DECLARES_EMPTY_NAME_ID);
}
}
IAnnotationDeclaration declaration = initializer.getInjectAnnotation();
/*
* 3.9.1. Declaring an initializer method
* - generic method of a bean is annotated @Inject
*/
if(CDIUtil.isMethodGeneric(initializer)) {
addProblem(CDIValidationMessages.GENERIC_METHOD_ANNOTATED_INJECT[getVersionIndex(initializer)], CDIPreferences.GENERIC_METHOD_ANNOTATED_INJECT, declaration, initializer.getResource());
}
/*
* 3.9. Initializer methods
* - initializer method may not be static
*/
if(CDIUtil.isMethodStatic(initializer)) {
addProblem(CDIValidationMessages.STATIC_METHOD_ANNOTATED_INJECT[getVersionIndex(initializer)], CDIPreferences.GENERIC_METHOD_ANNOTATED_INJECT, declaration, initializer.getResource());
}
}
private void validateInjectionPoint(CDIValidationContext context, IInjectionPoint injection) {
ICDIProject cdiProject = context.getCdiProject();
if(injection instanceof IInjectionPointParameter && injection.isAnnotationPresent(CDIConstants.DISPOSES_ANNOTATION_TYPE_NAME)) {
//Disposer is validated separately
return;
}
/*
* 3.11. The qualifier @Named at injection points
* - injection point other than injected field declares a @Named annotation that does not specify the value member
*/
if(injection instanceof IInjectionPointParameter) {
IAnnotationDeclaration named = injection.getAnnotation(CDIConstants.NAMED_QUALIFIER_TYPE_NAME);
if (named != null) {
Object value = named.getMemberValue(null);
boolean valueExists = value != null && value.toString().trim().length() > 0;
if (!valueExists) {
addProblem(CDIValidationMessages.PARAM_INJECTION_DECLARES_EMPTY_NAME[getVersionIndex(injection)],
CDIPreferences.PARAM_INJECTION_DECLARES_EMPTY_NAME,
named,
injection.getResource(),
PARAM_INJECTION_DECLARES_EMPTY_NAME_ID);
}
}
}
ITextSourceReference declaration = injection.getInjectAnnotation();
if(declaration == null && injection instanceof IInjectionPointParameter) {
declaration = injection;
}
/*
* 5.2.2. Legal injection point types
* - injection point type is a type variable
*/
if(CDIUtil.isTypeVariable(injection, false)) {
addProblem(CDIValidationMessages.INJECTION_TYPE_IS_VARIABLE[getVersionIndex(injection)], CDIPreferences.INJECTION_TYPE_IS_VARIABLE, declaration, injection.getResource());
}
if(declaration!=null) {
Collection<IBean> beans = cdiProject.getBeans(true, injection);
ITextSourceReference reference = injection instanceof IInjectionPointParameter?injection:declaration;
/*
* 5.2.1. Unsatisfied and ambiguous dependencies
* - If an unsatisfied or unresolvable ambiguous dependency exists, the container automatically detects the problem and treats it as a deployment problem.
*/
IType type = getTypeOfInjection(injection);
if(!shouldIgnoreInjection(context, type, injection)) {
boolean instance = type!=null && CDIConstants.INSTANCE_TYPE_NAME.equals(type.getFullyQualifiedName());
if(!isAsYouTypeValidation()) {
String injectionFilePath = injection.getSourcePath().toString();
for (IBean bean : cdiProject.getBeans(false, injection)) {
if(shouldValidateType(bean.getBeanClass())) {
try {
getValidationContext().addLinkedCoreResource(SHORT_ID, injectionFilePath, bean.getSourcePath(), false);
} catch (NullPointerException e) {
throw new RuntimeException("bean exists=" + bean.getBeanClass().exists() + " resource= " + bean.getResource() + " injection= " + injection.getSourcePath(),e);
}
for (IParametedType parametedType : bean.getAllTypes()) {
IType beanType = parametedType.getType();
if(beanType!=null && !beanType.isBinary()) {
getValidationContext().addLinkedCoreResource(SHORT_ID, injectionFilePath, beanType.getPath(), false);
}
}
}
}
}
if(type!=null && beans.isEmpty() && !instance) {
addProblem(CDIValidationMessages.UNSATISFIED_INJECTION_POINTS[getVersionIndex(injection)], CDIPreferences.UNSATISFIED_OR_AMBIGUOUS_INJECTION_POINTS, reference, injection.getResource(), UNSATISFIED_INJECTION_POINTS_ID);
} else if(beans.size()>1 && !instance) {
addProblem(CDIValidationMessages.AMBIGUOUS_INJECTION_POINTS[getVersionIndex(injection)], CDIPreferences.UNSATISFIED_OR_AMBIGUOUS_INJECTION_POINTS, reference, injection.getResource(), AMBIGUOUS_INJECTION_POINTS_ID);
} else if(beans.size()==1) {
IBean bean = beans.iterator().next();
if(cdiProject.getVersion() == CDIVersion.CDI_1_0) {
/*
* CDI 1.0 specification, it is omitted since CDI 1.1:
* 5.2.4. Primitive types and null values
* - injection point of primitive type resolves to a bean that may have null values, such as a producer method with a non-primitive return type or a producer field with a non-primitive type
*/
if(bean.isNullable() && injection.getType()!=null && injection.getType().isPrimitive()) {
addProblem(CDIValidationMessages.INJECT_RESOLVES_TO_NULLABLE_BEAN[getVersionIndex(bean)], CDIPreferences.INJECT_RESOLVES_TO_NULLABLE_BEAN, reference, injection.getResource());
}
}
/*
* 5.1.4. Inter-module injection
* - a decorator can not be injected
* - an interceptor can not be injected
* It is not an error - container just never attempts to inject them.
*/
/*
* 5.4.1. Unproxyable bean types
* - If an injection point whose declared type cannot be proxied by the container resolves to a bean with a normal scope,
* the container automatically detects the problem and treats it as a deployment problem.
*/
if(bean.getScope()!=null && bean.getScope().isNorlmalScope() && injection.getType()!=null) {
// - Array types cannot be proxied by the container.
String typeSignature = injection.getType().getSignature();
int kind = Signature.getTypeSignatureKind(typeSignature);
if(kind == Signature.ARRAY_TYPE_SIGNATURE) {
addProblem(MessageFormat.format(CDIValidationMessages.UNPROXYABLE_BEAN_ARRAY_TYPE[getVersionIndex(injection)], injection.getType().getSimpleName(), bean.getElementName()), CDIPreferences.UNPROXYABLE_BEAN_TYPE, reference, injection.getResource());
} else if(injection.getType().isPrimitive()) {
// - Primitive types cannot be proxied by the container.
addProblem(MessageFormat.format(CDIValidationMessages.UNPROXYABLE_BEAN_PRIMITIVE_TYPE[getVersionIndex(injection)], injection.getType().getSimpleName(), bean.getElementName()), CDIPreferences.UNPROXYABLE_BEAN_TYPE, reference, injection.getResource());
} else if(injection.getType().getType().exists()){
try {
if(Flags.isFinal(injection.getType().getType().getFlags())) {
// - Classes which are declared final cannot be proxied by the container.
addProblem(MessageFormat.format(CDIValidationMessages.UNPROXYABLE_BEAN_FINAL_TYPE[getVersionIndex(injection)], injection.getType().getSimpleName(), bean.getElementName()), CDIPreferences.UNPROXYABLE_BEAN_TYPE, reference, injection.getResource());
} else {
IMethod[] methods = injection.getType().getType().getMethods();
boolean hasDefaultConstructor = false;
boolean hasConstructor = false;
for (IMethod method : methods) {
hasConstructor = hasConstructor || method.isConstructor();
hasDefaultConstructor = hasDefaultConstructor || (method.isConstructor() && !Flags.isPrivate(method.getFlags()) && method.getParameterNames().length==0);
if(Flags.isFinal(method.getFlags())) {
// - Classes which have final methods cannot be proxied by the container.
addProblem(MessageFormat.format(CDIValidationMessages.UNPROXYABLE_BEAN_TYPE_WITH_FM[getVersionIndex(injection)], injection.getType().getSimpleName(), bean.getElementName()), CDIPreferences.UNPROXYABLE_BEAN_TYPE, reference, injection.getResource());
hasDefaultConstructor = true;
break;
}
}
if(!hasDefaultConstructor && hasConstructor) {
// - Classes which don't have a non-private constructor with no parameters cannot be proxied by the container.
addProblem(MessageFormat.format(CDIValidationMessages.UNPROXYABLE_BEAN_TYPE_WITH_NPC[getVersionIndex(injection)], injection.getType().getSimpleName(), bean.getElementName()), CDIPreferences.UNPROXYABLE_BEAN_TYPE, reference, injection.getResource());
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
}
if(injection.getClassBean() instanceof IDecorator && injection.isDelegate() && bean instanceof IClassBean && bean.getBeanClass().exists()) {
try {
IType beanClass = bean.getBeanClass();
if(Flags.isFinal(beanClass.getFlags())) {
// 8.3. Decorator resolution
// - If a decorator matches a managed bean, and the managed bean class is declared final, the container automatically detects
// the problem and treats it as a deployment problem.
addProblem(MessageFormat.format(CDIValidationMessages.DECORATOR_RESOLVES_TO_FINAL_CLASS[getVersionIndex(injection)], bean.getElementName()), CDIPreferences.DECORATOR_RESOLVES_TO_FINAL_BEAN, reference, injection.getResource());
} else {
// 8.3. Decorator resolution
// - If a decorator matches a managed bean with a non-static, non-private, final method, and the decorator also implements that method,
// the container automatically detects the problem and treats it as a deployment problem.
IType decoratorClass = injection.getClassBean().getBeanClass();
IMethod[] methods = decoratorClass.getMethods();
boolean reported = false;
if(methods!=null) {
for (IMethod method : methods) {
if(!Flags.isPrivate(method.getFlags()) && !Flags.isStatic(method.getFlags())) {
IMethod[] beanMethods = beanClass.findMethods(method);
if(beanMethods!=null) {
for (IMethod beanMethod : beanMethods) {
int flags = beanMethod.getFlags();
if(!Flags.isPrivate(flags) && !Flags.isStatic(flags) && Flags.isFinal(flags)) {
String methodName = Signature.toString(beanMethod.getSignature(), beanMethod.getElementName(), beanMethod.getParameterNames(), false, false);
addProblem(MessageFormat.format(CDIValidationMessages.DECORATOR_RESOLVES_TO_FINAL_METHOD[getVersionIndex(bean)], bean.getElementName(), methodName), CDIPreferences.DECORATOR_RESOLVES_TO_FINAL_BEAN, reference, injection.getResource());
reported = true;
break;
}
}
if(reported) {
break;
}
}
}
}
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
}
}
/*
* 5.5.7. Injection point metadata
* - bean that declares any scope other than @Dependent has an injection point of type InjectionPoint and qualifier @Default
*/
if(type!=null && CDIConstants.INJECTIONPOINT_TYPE_NAME.equals(type.getFullyQualifiedName())) {
IScope beanScope = injection.getBean().getScope();
if(injection.hasDefaultQualifier() && beanScope!=null && !CDIConstants.DEPENDENT_ANNOTATION_TYPE_NAME.equals(beanScope.getSourceType().getFullyQualifiedName())) {
addProblem(CDIValidationMessages.ILLEGAL_SCOPE_WHEN_TYPE_INJECTIONPOINT_IS_INJECTED[getVersionIndex(injection)], CDIPreferences.ILLEGAL_SCOPE_WHEN_TYPE_INJECTIONPOINT_IS_INJECTED, reference, injection.getResource());
}
}
}
/*
* 8.1.2. Decorator delegate injection points
* - bean class that is not a decorator has an injection point annotated @Delegate
*/
if(!(injection.getClassBean() instanceof IDecorator) && injection.isDelegate()) {
ITextSourceReference reference = injection.getDelegateAnnotation();
addProblem(CDIValidationMessages.ILLEGAL_BEAN_DECLARING_DELEGATE[getVersionIndex(injection)], CDIPreferences.ILLEGAL_BEAN_DECLARING_DELEGATE, reference, injection.getResource());
}
}
private void validateNormalBeanScope(IBean bean) {
if(bean.getScope()!=null && bean.getScope().isNorlmalScope()) {
ITextSourceReference reference = null;
Collection<IScopeDeclaration> scopes = bean.getScopeDeclarations();
if(!scopes.isEmpty()) {
reference = scopes.iterator().next();
} else {
reference = bean.getNameLocation(false);
}
if(reference == null) {
return;
}
for (IParametedType type: bean.getLegalTypes()) {
// - Array types cannot be proxied by the container.
String typeSignature = type.getSignature();
int kind = Signature.getTypeSignatureKind(typeSignature);
if(kind == Signature.ARRAY_TYPE_SIGNATURE) {
if("Object[]".equals(type.getSimpleName()) && bean.getLegalTypes().size() > 1) continue; //There is another type
addProblem(MessageFormat.format(CDIValidationMessages.UNPROXYABLE_BEAN_ARRAY_TYPE_2[getVersionIndex(bean)], type.getSimpleName(), bean.getElementName()), CDIPreferences.UNPROXYABLE_BEAN_TYPE, reference, bean.getResource());
} else if(type.isPrimitive()) {
// - Primitive types cannot be proxied by the container.
addProblem(MessageFormat.format(CDIValidationMessages.UNPROXYABLE_BEAN_PRIMITIVE_TYPE_2[getVersionIndex(bean)], type.getSimpleName(), bean.getElementName()), CDIPreferences.UNPROXYABLE_BEAN_TYPE, reference, bean.getResource());
} else if(type.getType().exists() && !"java.lang.Object".equals(type.getType().getFullyQualifiedName())) {
try {
if(Flags.isFinal(type.getType().getFlags())) {
// - Classes which are declared final cannot be proxied by the container.
addProblem(MessageFormat.format(CDIValidationMessages.UNPROXYABLE_BEAN_FINAL_TYPE_2[getVersionIndex(bean)], type.getSimpleName(), bean.getElementName()), CDIPreferences.UNPROXYABLE_BEAN_TYPE, reference, bean.getResource());
} else {
IMethod[] methods = type.getType().getMethods();
boolean hasDefaultConstructor = false;
boolean hasConstructor = false;
for (IMethod method : methods) {
hasConstructor = hasConstructor || method.isConstructor();
hasDefaultConstructor = hasDefaultConstructor || (method.isConstructor() && !Flags.isPrivate(method.getFlags()) && method.getParameterNames().length==0);
if(Flags.isFinal(method.getFlags())) {
// - Classes which have final methods cannot be proxied by the container.
addProblem(MessageFormat.format(CDIValidationMessages.UNPROXYABLE_BEAN_TYPE_WITH_FM_2[getVersionIndex(bean)], type.getSimpleName(), bean.getElementName()), CDIPreferences.UNPROXYABLE_BEAN_TYPE, reference, bean.getResource());
hasDefaultConstructor = true;
break;
}
}
if(!hasDefaultConstructor && hasConstructor) {
// - Classes which don't have a non-private constructor with no parameters cannot be proxied by the container.
addProblem(MessageFormat.format(CDIValidationMessages.UNPROXYABLE_BEAN_TYPE_WITH_NPC_2[getVersionIndex(bean)], type.getSimpleName(), bean.getElementName()), CDIPreferences.UNPROXYABLE_BEAN_TYPE, reference, bean.getResource());
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
}
}
}
/**
* Validates class bean which may be both a session and decorator (or interceptor).
*
* @param bean
*/
private void validateMixedClassBean(IClassBean bean) {
ITextSourceReference sessionDeclaration = CDIUtil.getSessionDeclaration(bean);
ITextSourceReference decoratorDeclaration = bean.getAnnotation(CDIConstants.DECORATOR_STEREOTYPE_TYPE_NAME);
ITextSourceReference interceptorDeclaration = bean.getAnnotation(CDIConstants.INTERCEPTOR_ANNOTATION_TYPE_NAME);
if (sessionDeclaration != null) {
/*
* 3.2. Session beans
* - bean class of a session bean is annotated @Decorator
*/
if (decoratorDeclaration != null) {
addProblem(CDIValidationMessages.SESSION_BEAN_ANNOTATED_DECORATOR[getVersionIndex(bean)], CDIPreferences.SESSION_BEAN_ANNOTATED_INTERCEPTOR_OR_DECORATOR,
sessionDeclaration, bean.getResource(), SESSION_BEAN_ANNOTATED_DECORATOR_ID);
addProblem(CDIValidationMessages.SESSION_BEAN_ANNOTATED_DECORATOR[getVersionIndex(bean)], CDIPreferences.SESSION_BEAN_ANNOTATED_INTERCEPTOR_OR_DECORATOR,
decoratorDeclaration, bean.getResource(), SESSION_BEAN_ANNOTATED_DECORATOR_ID);
}
/*
* 3.2. Session beans
* - bean class of a session bean is annotated @Interceptor
*/
if (interceptorDeclaration != null) {
addProblem(CDIValidationMessages.SESSION_BEAN_ANNOTATED_INTERCEPTOR[getVersionIndex(bean)], CDIPreferences.SESSION_BEAN_ANNOTATED_INTERCEPTOR_OR_DECORATOR,
sessionDeclaration, bean.getResource(), SESSION_BEAN_ANNOTATED_INTERCEPTOR_ID);
addProblem(CDIValidationMessages.SESSION_BEAN_ANNOTATED_INTERCEPTOR[getVersionIndex(bean)], CDIPreferences.SESSION_BEAN_ANNOTATED_INTERCEPTOR_OR_DECORATOR,
interceptorDeclaration, bean.getResource(), SESSION_BEAN_ANNOTATED_INTERCEPTOR_ID);
}
}
}
private void validateSessionBean(ISessionBean bean) {
IAnnotationDeclaration declaration = CDIUtil.getDifferentScopeDeclarationThanDepentend(bean);
if (declaration != null) {
IType type = bean.getBeanClass();
try {
/*
* 3.2. Session beans
* - session bean with a parameterized bean class declares any scope other than @Dependent
*/
String[] typeVariables = type.getTypeParameterSignatures();
if (typeVariables.length > 0) {
addProblem(CDIValidationMessages.ILLEGAL_SCOPE_FOR_SESSION_BEAN_WITH_GENERIC_TYPE[getVersionIndex(bean)], CDIPreferences.ILLEGAL_SCOPE_FOR_BEAN,
declaration, bean.getResource());
} else {
if (bean.isStateless()) {
/*
* 3.2. Session beans
* - session bean specifies an illegal scope (a stateless session bean must belong to the @Dependent pseudo-scope)
*/
if (declaration != null) {
addProblem(CDIValidationMessages.ILLEGAL_SCOPE_FOR_STATELESS_SESSION_BEAN[getVersionIndex(bean)], CDIPreferences.ILLEGAL_SCOPE_FOR_BEAN,
declaration, bean.getResource());
}
} else if (bean.isSingleton()) {
/*
* 3.2. Session beans
* - session bean specifies an illegal scope (a singleton bean must belong to either the @ApplicationScoped scope or to the @Dependent pseudo-scope)
*/
if (declaration != null) {
declaration = CDIUtil.getDifferentScopeDeclarationThanApplicationScoped(bean);
}
if (declaration != null) {
addProblem(CDIValidationMessages.ILLEGAL_SCOPE_FOR_SINGLETON_SESSION_BEAN[getVersionIndex(bean)], CDIPreferences.ILLEGAL_SCOPE_FOR_BEAN,
declaration, bean.getResource());
}
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
/*
* 3.2.4. Specializing a session bean
* - session bean class annotated @Specializes does not directly extend the bean class of another session bean
*/
IAnnotationDeclaration specializesDeclaration = bean.getSpecializesAnnotationDeclaration();
if (specializesDeclaration != null) {
saveAllSuperTypesAsLinkedResources(bean);
IBean sBean = bean.getSpecializedBean();
if (sBean == null) {
// The specializing bean extends nothing
addProblem(CDIValidationMessages.ILLEGAL_SPECIALIZING_SESSION_BEAN[getVersionIndex(bean)], CDIPreferences.ILLEGAL_SPECIALIZING_BEAN, specializesDeclaration,
bean.getResource());
} else if (!CDIUtil.isSessionBean(sBean)) {
// The specializing bean directly extends a non-session bean class
addProblem(CDIValidationMessages.ILLEGAL_SPECIALIZING_SESSION_BEAN[getVersionIndex(bean)], CDIPreferences.ILLEGAL_SPECIALIZING_BEAN, specializesDeclaration,
bean.getResource());
}
}
}
private void validateManagedBean(IClassBean bean) {
/*
* 3.1. Managed beans
* - the bean class of a managed bean is annotated with both the @Interceptor and @Decorator stereotypes
*/
IAnnotationDeclaration decorator = bean.getAnnotation(CDIConstants.DECORATOR_STEREOTYPE_TYPE_NAME);
IAnnotationDeclaration interceptor = bean.getAnnotation(CDIConstants.INTERCEPTOR_ANNOTATION_TYPE_NAME);
if (decorator != null && interceptor != null) {
addProblem(CDIValidationMessages.BOTH_INTERCEPTOR_AND_DECORATOR[getVersionIndex(bean)], CDIPreferences.BOTH_INTERCEPTOR_AND_DECORATOR, decorator, bean.getResource());
addProblem(CDIValidationMessages.BOTH_INTERCEPTOR_AND_DECORATOR[getVersionIndex(bean)], CDIPreferences.BOTH_INTERCEPTOR_AND_DECORATOR, interceptor, bean.getResource());
}
IAnnotationDeclaration declaration = CDIUtil.getDifferentScopeDeclarationThanDepentend(bean);
if (declaration != null) {
IType type = bean.getBeanClass();
try {
/*
* 3.1. Managed beans
* - managed bean with a public field declares any scope other than @Dependent
*/
IField[] fields = type.getFields();
for (IField field : fields) {
if (Flags.isPublic(field.getFlags()) && !Flags.isStatic(field.getFlags())) {
ITextSourceReference fieldReference = CDIUtil.convertToSourceReference(field.getNameRange(), bean.getResource(), field);
addProblem(CDIValidationMessages.ILLEGAL_SCOPE_FOR_MANAGED_BEAN_WITH_PUBLIC_FIELD[getVersionIndex(bean)], CDIPreferences.ILLEGAL_SCOPE_FOR_BEAN,
fieldReference, bean.getResource(), ILLEGAL_SCOPE_FOR_MANAGED_BEAN_WITH_PUBLIC_FIELD_ID);
}
}
/*
* 3.1. Managed beans
* - managed bean with a parameterized bean class declares any scope other than @Dependent
*/
String[] typeVariables = type.getTypeParameterSignatures();
if (typeVariables.length > 0) {
addProblem(CDIValidationMessages.ILLEGAL_SCOPE_FOR_MANAGED_BEAN_WITH_GENERIC_TYPE[getVersionIndex(bean)], CDIPreferences.ILLEGAL_SCOPE_FOR_BEAN,
declaration, bean.getResource());
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
/*
* 3.1.4. Specializing a managed bean
* - managed bean class annotated @Specializes does not directly extend the bean class of another managed bean
*/
IAnnotationDeclaration specializesDeclaration = bean.getSpecializesAnnotationDeclaration();
if (specializesDeclaration != null) {
saveAllSuperTypesAsLinkedResources(bean);
IBean sBean = bean.getSpecializedBean();
if (sBean != null) {
if (sBean instanceof ISessionBean || sBean.getAnnotation(CDIConstants.STATELESS_ANNOTATION_TYPE_NAME) != null
|| sBean.getAnnotation(CDIConstants.SINGLETON_ANNOTATION_TYPE_NAME) != null) {
// The specializing bean directly extends an enterprise bean class
addProblem(CDIValidationMessages.ILLEGAL_SPECIALIZING_MANAGED_BEAN[getVersionIndex(bean)], CDIPreferences.ILLEGAL_SPECIALIZING_BEAN,
specializesDeclaration, bean.getResource());
} else {
// Validate the specializing bean extends a non simple bean
if (sBean instanceof ClassBean && !((ClassBean)sBean).getDefinition().hasBeanConstructor()) {
addProblem(CDIValidationMessages.ILLEGAL_SPECIALIZING_MANAGED_BEAN[getVersionIndex(bean)], CDIPreferences.ILLEGAL_SPECIALIZING_BEAN, specializesDeclaration, bean.getResource());
}
}
} else {
// The specializing bean extends nothing
addProblem(CDIValidationMessages.ILLEGAL_SPECIALIZING_MANAGED_BEAN[getVersionIndex(bean)], CDIPreferences.ILLEGAL_SPECIALIZING_BEAN, specializesDeclaration, bean.getResource());
}
}
try {
/*
* 9.3. Binding an interceptor to a bean
* - managed bean has a class level interceptor binding and is declared final or has a non-static, non-private, final method
* - non-static, non-private, final method of a managed bean has a method level interceptor binding
*/
Collection<IInterceptorBinding> bindings = bean.getInterceptorBindings();
if(!bindings.isEmpty()) {
if(Flags.isFinal(bean.getBeanClass().getFlags())) {
ITextSourceReference reference = CDIUtil.convertToSourceReference(bean.getBeanClass().getNameRange(), bean.getResource(), bean.getBeanClass());
addProblem(CDIValidationMessages.ILLEGAL_INTERCEPTOR_BINDING_CLASS[getVersionIndex(bean)], CDIPreferences.ILLEGAL_INTERCEPTOR_BINDING_METHOD, reference, bean.getResource());
} else {
IMethod[] methods = bean.getBeanClass().getMethods();
for (int i = 0; i < methods.length; i++) {
int flags = methods[i].getFlags();
if(Flags.isFinal(flags) && !Flags.isStatic(flags) && !Flags.isPrivate(flags)) {
ITextSourceReference reference = CDIUtil.convertToSourceReference(methods[i].getNameRange(), bean.getResource(), methods[i]);
addProblem(CDIValidationMessages.ILLEGAL_INTERCEPTOR_BINDING_METHOD[getVersionIndex(bean)], CDIPreferences.ILLEGAL_INTERCEPTOR_BINDING_METHOD, reference, bean.getResource());
}
}
}
} else {
for (IBeanMethod method : bean.getAllMethods()) {
if(!method.getInterceptorBindings().isEmpty()) {
if(Flags.isFinal(bean.getBeanClass().getFlags())) {
ITextSourceReference reference = CDIUtil.convertToSourceReference(bean.getBeanClass().getNameRange(), bean.getResource(), bean.getBeanClass());
addProblem(CDIValidationMessages.ILLEGAL_INTERCEPTOR_BINDING_CLASS[getVersionIndex(bean)], CDIPreferences.ILLEGAL_INTERCEPTOR_BINDING_METHOD, reference, bean.getResource());
} else {
IMethod sourceMethod = method.getMethod();
int flags = sourceMethod.getFlags();
if(Flags.isFinal(flags) && !Flags.isStatic(flags) && !Flags.isPrivate(flags)) {
ITextSourceReference reference = CDIUtil.convertToSourceReference(sourceMethod.getNameRange(), bean.getResource(), sourceMethod);
addProblem(CDIValidationMessages.ILLEGAL_INTERCEPTOR_BINDING_METHOD[getVersionIndex(bean)], CDIPreferences.ILLEGAL_INTERCEPTOR_BINDING_METHOD, reference, bean.getResource());
}
}
}
}
}
/*
* 6.6.4 Validation of passivation capable beans and dependencies
* - If a managed bean which declares a passivating scope is not passivation capable, then the container automatically detects the problem and treats it as a deployment problem.
*/
if(bean.getScopeDeclarations().size()<2) { // Ignore broken beans with multiple scope declarations.
IScope scope = bean.getScope();
if(scope!=null && scope.isNorlmalScope()) {
IAnnotationDeclaration normalScopeDeclaration = scope.getAnnotationDeclaration(CDIConstants.NORMAL_SCOPE_ANNOTATION_TYPE_NAME);
if(normalScopeDeclaration != null) {
boolean passivatingScope = "true".equalsIgnoreCase("" + normalScopeDeclaration.getMemberValue("passivating"));
if(passivatingScope) {
boolean passivatingCapable = false;
for (IParametedType type : bean.getAllTypes()) {
if("java.io.Serializable".equals(type.getType().getFullyQualifiedName())) {
passivatingCapable = true;
break;
}
}
if(!passivatingCapable) {
ITextSourceReference reference = CDIUtil.convertToSourceReference(bean.getBeanClass().getNameRange(), bean.getResource(), bean.getBeanClass());
addProblem(MessageFormat.format(CDIValidationMessages.NOT_PASSIVATION_CAPABLE_BEAN[getVersionIndex(bean)], bean.getElementName(), scope.getSourceType().getElementName()), CDIPreferences.NOT_PASSIVATION_CAPABLE_BEAN, reference, bean.getResource(), NOT_PASSIVATION_CAPABLE_BEAN_ID);
}
}
}
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
private void validateInterceptor(IInterceptor interceptor) {
/*
* 2.5.3. Beans with no EL name
* - interceptor has a name (Non-Portable behavior)
*/
if (interceptor.getName() != null) {
ITextSourceReference declaration = interceptor.getAnnotation(CDIConstants.NAMED_QUALIFIER_TYPE_NAME);
if (declaration == null) {
declaration = interceptor.getAnnotation(CDIConstants.INTERCEPTOR_ANNOTATION_TYPE_NAME);
}
if (declaration == null) {
declaration = CDIUtil.getNamedStereotypeDeclaration(interceptor);
}
addProblem(CDIValidationMessages.INTERCEPTOR_HAS_NAME[getVersionIndex(interceptor)], CDIPreferences.INTERCEPTOR_OR_DECORATOR_HAS_NAME, declaration, interceptor.getResource(), INTERCEPTOR_HAS_NAME_ID);
}
/*
* 2.6.1. Declaring an alternative
* - interceptor is an alternative (Non-Portable behavior)
*/
if (interceptor.isAlternative()) {
ITextSourceReference declaration = interceptor.getAlternativeDeclaration();
if (declaration == null) {
declaration = interceptor.getInterceptorAnnotation();
}
if(declaration == null) {
//for custom implementations
declaration = interceptor.getNameLocation(true);
}
addProblem(CDIValidationMessages.INTERCEPTOR_IS_ALTERNATIVE[getVersionIndex(interceptor)], CDIPreferences.INTERCEPTOR_OR_DECORATOR_IS_ALTERNATIVE, declaration, interceptor
.getResource());
}
/*
* 3.3.2. Declaring a producer method
* - interceptor has a method annotated @Produces
*
* 3.4.2. Declaring a producer field
* - interceptor has a field annotated @Produces
*/
for (IProducer producer : interceptor.getProducers()) {
addProblem(CDIValidationMessages.PRODUCER_IN_INTERCEPTOR[getVersionIndex(producer)], CDIPreferences.PRODUCER_IN_INTERCEPTOR_OR_DECORATOR, producer.getProducesAnnotation(), interceptor.getResource(), PRODUCER_IN_INTERCEPTOR_ID);
}
/*
* 9.2. Declaring the interceptor bindings of an interceptor
* - interceptor declared using @Interceptor does not declare any interceptor binding (Non-Portable behavior)
*/
Collection<IInterceptorBinding> bindings = interceptor.getInterceptorBindings();
if(bindings.isEmpty()) {
ITextSourceReference declaration = interceptor.getAnnotation(CDIConstants.INTERCEPTOR_ANNOTATION_TYPE_NAME);
if(declaration!=null) {
addProblem(CDIValidationMessages.MISSING_INTERCEPTOR_BINDING[getVersionIndex(interceptor)], CDIPreferences.MISSING_INTERCEPTOR_BINDING, declaration, interceptor.getResource());
}
} else {
/*
* 9.2. Declaring the interceptor bindings of an interceptor
* - interceptor for lifecycle callbacks declares an interceptor binding type that is defined @Target({TYPE, METHOD})
*/
for (IInterceptorBinding binding : bindings) {
boolean markedAsWrong = false;
IAnnotationDeclaration target = binding.getAnnotationDeclaration(CDIConstants.TARGET_ANNOTATION_TYPE_NAME);
if(target!=null) {
Object value = target.getMemberValue(null);
if(value instanceof Object[]) {
Object[] values = (Object[]) value;
if(values.length>1) {
for (IBeanMethod method : interceptor.getAllMethods()) {
if(method.isLifeCycleCallbackMethod()) {
ITextSourceReference declaration = CDIUtil.getAnnotationDeclaration(interceptor, binding);
if(declaration==null) {
declaration = interceptor.getInterceptorAnnotation();
}
addProblem(CDIValidationMessages.ILLEGAL_LIFECYCLE_CALLBACK_INTERCEPTOR_BINDING[getVersionIndex(interceptor)], CDIPreferences.ILLEGAL_LIFECYCLE_CALLBACK_INTERCEPTOR_BINDING, declaration, interceptor.getResource());
markedAsWrong = true;
break;
}
}
}
}
}
if(markedAsWrong) {
break;
}
}
}
}
private void validateDecorator(CDIValidationContext context, IDecorator decorator) {
/*
* 2.5.3. Beans with no EL name
* - decorator has a name (Non-Portable behavior)
*/
if (decorator.getName() != null) {
ITextSourceReference declaration = decorator.getAnnotation(CDIConstants.NAMED_QUALIFIER_TYPE_NAME);
if (declaration == null) {
declaration = decorator.getAnnotation(CDIConstants.DECORATOR_STEREOTYPE_TYPE_NAME);
}
if (declaration == null) {
declaration = CDIUtil.getNamedStereotypeDeclaration(decorator);
}
addProblem(CDIValidationMessages.DECORATOR_HAS_NAME[getVersionIndex(decorator)], CDIPreferences.INTERCEPTOR_OR_DECORATOR_HAS_NAME, declaration, decorator.getResource(), DECORATOR_HAS_NAME_ID);
}
/*
* 2.6.1. Declaring an alternative
* - decorator is an alternative (Non-Portable behavior)
*/
if (decorator.isAlternative()) {
ITextSourceReference declaration = decorator.getAlternativeDeclaration();
if (declaration == null) {
declaration = decorator.getDecoratorAnnotation();
}
if(declaration == null) {
//for custom implementations
declaration = decorator.getNameLocation(true);
}
addProblem(CDIValidationMessages.DECORATOR_IS_ALTERNATIVE[getVersionIndex(decorator)], CDIPreferences.INTERCEPTOR_OR_DECORATOR_IS_ALTERNATIVE, declaration, decorator.getResource());
}
/*
* 3.3.2. Declaring a producer method
* - decorator has a method annotated @Produces
*
* 3.4.2. Declaring a producer field
* - decorator has a field annotated @Produces
*/
for (IProducer producer : decorator.getProducers()) {
addProblem(CDIValidationMessages.PRODUCER_IN_DECORATOR[getVersionIndex(decorator)], CDIPreferences.PRODUCER_IN_INTERCEPTOR_OR_DECORATOR, producer.getProducesAnnotation(), decorator.getResource(), PRODUCER_IN_DECORATOR_ID);
}
Set<ITextSourceReference> delegates = new HashSet<ITextSourceReference>();
IInjectionPoint delegate = null;
for (IInjectionPoint injection : decorator.getInjectionPoints(true)) {
ITextSourceReference delegateAnnotation = injection.getDelegateAnnotation();
if(delegateAnnotation!=null) {
if(injection instanceof IInjectionPointField) {
delegate = injection;
delegates.add(delegateAnnotation);
}
if(injection instanceof IInjectionPointParameter) {
if(((IInjectionPointParameter) injection).getBeanMethod().getAnnotation(CDIConstants.PRODUCES_ANNOTATION_TYPE_NAME)==null) {
delegate = injection;
delegates.add(delegateAnnotation);
} else {
/*
* 8.1.2. Decorator delegate injection points
* - injection point that is not an injected field, initializer method parameter or bean constructor method parameter is annotated @Delegate
*/
addProblem(CDIValidationMessages.ILLEGAL_INJECTION_POINT_DELEGATE[getVersionIndex(decorator)], CDIPreferences.ILLEGAL_INJECTION_POINT_DELEGATE, delegateAnnotation, decorator.getResource());
}
}
}
}
if(delegates.size()>1) {
/*
* 8.1.2. Decorator delegate injection points
* - decorator has more than one delegate injection point
*/
for (ITextSourceReference declaration : delegates) {
addProblem(CDIValidationMessages.MULTIPLE_DELEGATE[getVersionIndex(decorator)], CDIPreferences.MULTIPLE_OR_MISSING_DELEGATE, declaration, decorator.getResource());
}
} else if(delegates.isEmpty()) {
/*
* 8.1.2. Decorator delegate injection points
* - decorator does not have a delegate injection point
*/
IAnnotationDeclaration declaration = decorator.getDecoratorAnnotation();
addProblem(CDIValidationMessages.MISSING_DELEGATE[getVersionIndex(decorator)], CDIPreferences.MULTIPLE_OR_MISSING_DELEGATE, declaration, decorator.getResource());
}
/*
* 8.1.3. Decorator delegate injection points
* - delegate type does not implement or extend a decorated type of the decorator, or specifies different type parameters
*/
if(delegate!=null) {
IParametedType delegateParametedType = delegate.getType();
if(delegateParametedType!=null) {
IType delegateType = delegateParametedType.getType();
if(delegateType != null) {
if(!checkTheOnlySuper(context, decorator, delegateParametedType)) {
List<String> supers = null;
if(!isAsYouTypeValidation() && shouldValidateType(delegateType)) {
getValidationContext().addLinkedCoreResource(SHORT_ID, decorator.getSourcePath().toString(), delegateType.getResource().getFullPath(), false);
}
for (IParametedType decoratedParametedType : decorator.getDecoratedTypes()) {
IType decoratedType = decoratedParametedType.getType();
if(decoratedType==null) {
continue;
}
if(!isAsYouTypeValidation() && shouldValidateType(decoratedType)) {
getValidationContext().addLinkedCoreResource(SHORT_ID, decorator.getSourcePath().toString(), decoratedType.getResource().getFullPath(), false);
}
String decoratedTypeName = decoratedType.getFullyQualifiedName();
// Ignore the type of the decorator class bean
if(decoratedTypeName.equals(decorator.getBeanClass().getFullyQualifiedName())) {
continue;
}
if(decoratedTypeName.equals("java.lang.Object")) { //$NON-NLS-1$
continue;
}
if(supers==null) {
supers = getSuppers(delegateParametedType);
}
if(supers.contains(decoratedParametedType.getSignature())) {
continue;
} else {
ITextSourceReference declaration = delegate.getDelegateAnnotation();
if(delegateParametedType instanceof ITypeDeclaration) {
declaration = CDIUtil.convertToJavaSourceReference((ITypeDeclaration)delegateParametedType, delegate.getSourceMember());
}
String typeName = Signature.getSignatureSimpleName(decoratedParametedType.getSignature());
addProblem(MessageFormat.format(CDIValidationMessages.DELEGATE_HAS_ILLEGAL_TYPE[getVersionIndex(decorator)], typeName), CDIPreferences.DELEGATE_HAS_ILLEGAL_TYPE, declaration, decorator.getResource());
break;
}
}
}
}
}
}
}
private boolean checkTheOnlySuper(CDIValidationContext context, IDecorator decorator, IParametedType delegatedType) {
ICDIProject cdiProject = context.getCdiProject();
try {
String superClassSignature = decorator.getBeanClass().getSuperclassTypeSignature();
String[] superInterfaceSignatures = decorator.getBeanClass().getSuperInterfaceTypeSignatures();
if(superClassSignature==null) {
if(superInterfaceSignatures.length==0) {
return true;
}
if(superInterfaceSignatures.length>1) {
return false;
}
IParametedType superType = cdiProject.getNature().getTypeFactory().getParametedType(decorator.getBeanClass(), superInterfaceSignatures[0]);
return superType==null?true:superType.getSignature().equals(delegatedType.getSignature());
} else if(superInterfaceSignatures.length>0) {
return false;
}
IParametedType superType = cdiProject.getNature().getTypeFactory().getParametedType(decorator.getBeanClass(), superClassSignature);
if(superType!=null) {
superType.getSignature().equals(delegatedType.getSignature());
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
return true;
}
private List<String> getSuppers(IParametedType type) {
List<String> signatures = new ArrayList<String>();
for (IParametedType superType : ((ParametedType)type).getAllTypes()) {
signatures.add(superType.getSignature());
}
signatures.add(type.getSignature());
return signatures;
}
/*
* 2.2.2. Restricting the bean types of a bean
* - bean class or producer method or field specifies a @Typed annotation, and the value member specifies a class which does not correspond to a type in the unrestricted set of bean types of a bean
*/
private void validateTyped(IBean bean) {
Collection<ITypeDeclaration> typedDeclarations = bean.getRestrictedTypeDeclaratios();
if (!typedDeclarations.isEmpty()) {
saveAllSuperTypesAsLinkedResources(bean);
Set<String> allTypeNames = new HashSet<String>();
for (IParametedType type : bean.getAllTypes()) {
if(type.getType() != null) allTypeNames.add(type.getType().getFullyQualifiedName());
}
for (ITypeDeclaration typedDeclaration : typedDeclarations) {
IType typedType = typedDeclaration.getType();
if (typedType != null && !allTypeNames.contains(typedType.getFullyQualifiedName())) {
IMember e = bean instanceof IJavaReference ? ((IJavaReference)bean).getSourceMember() : bean.getBeanClass();
ITextSourceReference typedDeclarationReference = CDIUtil.convertToJavaSourceReference(typedDeclaration, e);
String message = CDIValidationMessages.ILLEGAL_TYPE_IN_TYPED_DECLARATION[getVersionIndex(bean)];
addProblem(message, CDIPreferences.ILLEGAL_TYPE_IN_TYPED_DECLARATION, typedDeclarationReference, bean.getResource());
}
}
}
}
private void validateBeanScope(IBean bean) {
Collection<IScopeDeclaration> scopes = bean.getScopeDeclarations();
// 2.4.3. Declaring the bean scope
// - bean class or producer method or field specifies multiple scope type annotations
//
if (scopes.size() > 1) {
String message = bean instanceof IClassBean
? CDIValidationMessages.MULTIPLE_SCOPE_TYPE_ANNOTATIONS_IN_BEAN_CLASS[getVersionIndex(bean)]
: bean instanceof IProducerField
? CDIValidationMessages.MULTIPLE_SCOPE_TYPE_ANNOTATIONS_IN_PRODUCER_FIELD[getVersionIndex(bean)]
: bean instanceof IProducerMethod
? CDIValidationMessages.MULTIPLE_SCOPE_TYPE_ANNOTATIONS_IN_PRODUCER_METHOD[getVersionIndex(bean)]
: CDIValidationMessages.MULTIPLE_SCOPE_TYPE_ANNOTATIONS[getVersionIndex(bean)];
for (IScopeDeclaration scope : scopes) {
addProblem(message, CDIPreferences.MULTIPLE_SCOPE_TYPE_ANNOTATIONS, scope, bean.getResource());
}
}
// 2.4.4. Default scope
// - bean does not explicitly declare a scope when there is no default scope (there are two different stereotypes declared by the bean that declare different default scopes)
//
// Such bean definitions are invalid because they declares two
// stereotypes that have different default scopes and the bean does not
// explictly define a scope to resolve the conflict.
Collection<IStereotypeDeclaration> stereotypeDeclarations = bean.getStereotypeDeclarations();
if (!stereotypeDeclarations.isEmpty() && scopes.isEmpty()) {
Map<String, IStereotypeDeclaration> declarationMap = new HashMap<String, IStereotypeDeclaration>();
for (IStereotypeDeclaration stereotypeDeclaration : stereotypeDeclarations) {
IStereotype stereotype = stereotypeDeclaration.getStereotype();
IScope scope = stereotype != null ? stereotype.getScope() : null;
if (scope != null) {
declarationMap.put(scope.getSourceType().getFullyQualifiedName(), stereotypeDeclaration);
}
}
if (declarationMap.size() > 1) {
for (IStereotypeDeclaration stereotypeDeclaration : declarationMap.values()) {
addProblem(CDIValidationMessages.MISSING_SCOPE_WHEN_THERE_IS_NO_DEFAULT_SCOPE[getVersionIndex(bean)], CDIPreferences.MISSING_SCOPE_WHEN_THERE_IS_NO_DEFAULT_SCOPE, stereotypeDeclaration, bean.getResource());
}
}
}
/*
* 2.4.1. Built-in scope types
* - interceptor or decorator has any scope other than @Dependent (Non-Portable behavior)
*/
boolean interceptor = bean instanceof IInterceptor;
boolean decorator = bean instanceof IDecorator;
if (interceptor || decorator) {
IAnnotationDeclaration scopeOrStereotypeDeclaration = CDIUtil.getDifferentScopeDeclarationThanDepentend(bean);
if (scopeOrStereotypeDeclaration != null) {
String message = interceptor?CDIValidationMessages.ILLEGAL_SCOPE_FOR_INTERCEPTOR[getVersionIndex(bean)]:CDIValidationMessages.ILLEGAL_SCOPE_FOR_DECORATOR[getVersionIndex(bean)];
addProblem(message, CDIPreferences.ILLEGAL_SCOPE_FOR_INTERCEPTOR_OR_DECORATOR, scopeOrStereotypeDeclaration, bean.getResource());
}
}
}
boolean shouldValidateResourceOfElement(IResource resource) {
// validate existing sources only
if(resource instanceof IFile && !shouldBeValidated((IFile)resource)) {
return false;
}
return resource != null && resource.exists() && resource.getName().toLowerCase().endsWith(".java");
}
boolean shouldValidateType(IType type) {
return type.exists() && !type.isReadOnly();
}
/**
* Validates a stereotype.
*
* @param type
*/
private void validateStereotype(IStereotype stereotype) {
// 2.7.1.3. Declaring a @Named stereotype
// - stereotype declares a non-empty @Named annotation (Non-Portable
// behavior)
// - stereotype declares any other qualifier annotation
// - stereotype is annotated @Typed
if(stereotype==null) {
return;
}
IResource resource = stereotype.getResource();
if(!shouldValidateResourceOfElement(resource)) {
return;
}
addLinkedStereotypes(stereotype.getSourcePath().toString(), stereotype);
List<IAnnotationDeclaration> as = stereotype.getAnnotationDeclarations();
// 1. non-empty name
IAnnotationDeclaration nameDeclaration = stereotype.getNameDeclaration();
if (nameDeclaration != null) {
Object name = nameDeclaration.getMemberValue(null);
if (name != null && name.toString().length() > 0) {
ITextSourceReference location = nameDeclaration;
addProblem(CDIValidationMessages.STEREOTYPE_DECLARES_NON_EMPTY_NAME[getVersionIndex(stereotype)], CDIPreferences.STEREOTYPE_DECLARES_NON_EMPTY_NAME, location, resource, STEREOTYPE_DECLARES_NON_EMPTY_NAME_ID);
}
}
// 2. typed annotation
IAnnotationDeclaration typedDeclaration = stereotype.getAnnotationDeclaration(CDIConstants.TYPED_ANNOTATION_TYPE_NAME);
if (typedDeclaration != null) {
ITextSourceReference location = typedDeclaration;
addProblem(CDIValidationMessages.STEREOTYPE_IS_ANNOTATED_TYPED[getVersionIndex(stereotype)], CDIPreferences.STEREOTYPE_IS_ANNOTATED_TYPED, location, resource, STEREOTYPE_IS_ANNOTATED_TYPED_ID);
}
// 3. Qualifier other than @Named
for (IAnnotationDeclaration a : as) {
if (a instanceof IQualifierDeclaration && a != nameDeclaration) {
ITextSourceReference location = a;
addProblem(CDIValidationMessages.ILLEGAL_QUALIFIER_IN_STEREOTYPE[getVersionIndex(stereotype)], CDIPreferences.ILLEGAL_QUALIFIER_IN_STEREOTYPE, location, resource);
}
}
// 2.7.1.1. Declaring the default scope for a stereotype
// - stereotype declares more than one scope
Collection<IScopeDeclaration> scopeDeclarations = stereotype.getScopeDeclarations();
if (scopeDeclarations.size() > 1) {
for (IScopeDeclaration scope : scopeDeclarations) {
addProblem(CDIValidationMessages.STEREOTYPE_DECLARES_MORE_THAN_ONE_SCOPE[getVersionIndex(stereotype)], CDIPreferences.STEREOTYPE_DECLARES_MORE_THAN_ONE_SCOPE, scope, stereotype.getResource());
}
}
try {
annotationValidator.validateStereotypeAnnotationTypeAnnotations(stereotype, resource);
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
boolean shouldValidateAnnotation(ICDIAnnotation annotation) {
return annotation!=null && annotation.getSourceType() != null && shouldValidateType(annotation.getSourceType());
}
private void validateInterceptorBinding(IInterceptorBinding binding) {
if(binding==null || !shouldValidateAnnotation(binding)) {
return;
}
addLinkedInterceptorBindings(binding.getSourcePath().toString(), binding);
/*
* 9.5.2. Interceptor binding types with members
* array-valued or annotation-valued member of an interceptor binding type is not annotated @Nonbinding (Non-Portable behavior)
*/
validateAnnotationMembers(
binding,
CDIValidationMessages.MISSING_NONBINDING_FOR_ARRAY_VALUE_IN_INTERCEPTOR_BINDING_TYPE_MEMBER[getVersionIndex(binding)],
CDIValidationMessages.MISSING_NONBINDING_FOR_ANNOTATION_VALUE_IN_INTERCEPTOR_BINDING_TYPE_MEMBER[getVersionIndex(binding)],
CDIPreferences.MISSING_NONBINDING_IN_INTERCEPTOR_BINDING_TYPE_MEMBER,
MISSING_NONBINDING_FOR_ARRAY_VALUE_IN_INTERCEPTOR_BINDING_TYPE_MEMBER_ID,
MISSING_NONBINDING_FOR_ANNOTATION_VALUE_IN_INTERCEPTOR_BINDING_TYPE_MEMBER_ID);
try {
annotationValidator.validateInterceptorBindingAnnotationTypeAnnotations(binding);
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
/**
* Validates a qualifier.
*
* @param qualifier
*/
private void validateQualifier(IQualifier qualifier) {
if(qualifier==null) {
return;
}
IResource resource = qualifier.getResource();
if(!shouldValidateResourceOfElement(resource)) {
return;
}
/*
* 5.2.5. Qualifier annotations with members
* - array-valued or annotation-valued member of a qualifier type is not annotated @Nonbinding (Non-Portable behavior)
*/
validateAnnotationMembers(
qualifier,
CDIValidationMessages.MISSING_NONBINDING_FOR_ARRAY_VALUE_IN_QUALIFIER_TYPE_MEMBER[getVersionIndex(qualifier)],
CDIValidationMessages.MISSING_NONBINDING_FOR_ANNOTATION_VALUE_IN_QUALIFIER_TYPE_MEMBER[getVersionIndex(qualifier)],
CDIPreferences.MISSING_NONBINDING_IN_QUALIFIER_TYPE_MEMBER,
MISSING_NONBINDING_FOR_ARRAY_VALUE_IN_QUALIFIER_TYPE_MEMBER_ID,
MISSING_NONBINDING_FOR_ANNOTATION_VALUE_IN_QUALIFIER_TYPE_MEMBER_ID);
/*
* Qualifier annotation type should be annotated with @Target({METHOD, FIELD, PARAMETER, TYPE})
*/
try {
annotationValidator.validateQualifierAnnotationTypeAnnotations(qualifier, resource);
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
void validateAnnotationMembers(ICDIAnnotation annotation, String arrayMessageErrorKey, String annotationValueErrorKey, String preferencesKey, int arrayMessageId, int annotationValueId) {
IType type = annotation.getSourceType();
try {
IMethod[] methods = type.getMethods();
for (IMethod method : methods) {
String returnTypeSignature = method.getReturnType();
int kind = Signature.getTypeSignatureKind(returnTypeSignature);
if(kind == Signature.ARRAY_TYPE_SIGNATURE) {
if(!annotation.getNonBindingMethods().contains(method)) {
ITextSourceReference reference = CDIUtil.convertToSourceReference(method.getNameRange(), annotation.getResource(), method);
addProblem(arrayMessageErrorKey, preferencesKey, reference, annotation.getResource(), arrayMessageId);
}
} else if(kind == Signature.CLASS_TYPE_SIGNATURE) {
String typeName = Signature.getSignatureSimpleName(returnTypeSignature);
String packageName = Signature.getSignatureQualifier(returnTypeSignature);
if(packageName.length()>0) {
typeName = packageName + "." + typeName;
} else {
typeName = EclipseJavaUtil.resolveType(type, typeName);
}
if(typeName!=null) {
IType memberType = type.getJavaProject().findType(typeName);
if(memberType!=null && memberType.isAnnotation()) {
if(!annotation.getNonBindingMethods().contains(method)) {
ITextSourceReference reference = CDIUtil.convertToSourceReference(method.getNameRange(), annotation.getResource(), method);
addProblem(annotationValueErrorKey, preferencesKey, reference, annotation.getResource(), annotationValueId);
}
}
}
}
}
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
private static final String BUNDLE_NAME = "org.jboss.tools.cdi.internal.core.validation.messages";
/*
* (non-Javadoc)
* @see org.jboss.tools.common.validation.TempMarkerManager#getMessageBundleName()
*/
@Override
protected String getMessageBundleName() {
return BUNDLE_NAME;
}
/*
* (non-Javadoc)
* @see org.jboss.tools.common.validation.TempMarkerManager#shouldCleanAllAnnotations()
*/
@Override
protected boolean shouldCleanAllAnnotations() {
return true;
}
@Override
public void registerPreferenceInfo() {
PreferenceInfoManager.register(getProblemType(), new CDIPreferenceInfo());
}
class CDIPreferenceInfo implements IPreferenceInfo{
@Override
public String getPreferencePageId() {
return PREFERENCE_PAGE_ID;
}
@Override
public String getPropertyPageId() {
return PROPERTY_PAGE_ID;
}
@Override
public String getPluginId() {
return CDICorePlugin.PLUGIN_ID;
}
}
}