Bug 483566 - [preferences] UI for multiple sets of null annotation names

Change-Id: Ibe331021dd4d176e1e90055b16cfd30b8bf389d1
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/TypeContextChecker.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/TypeContextChecker.java
index 849217d..762d63b 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/TypeContextChecker.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/TypeContextChecker.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -23,6 +23,8 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.NullProgressMonitor;
 
+import org.eclipse.core.resources.IProject;
+
 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
 
 import org.eclipse.jdt.core.Flags;
@@ -30,9 +32,11 @@
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IMethod;
 import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.ISourceRange;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.ITypeParameter;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.WorkingCopyOwner;
 import org.eclipse.jdt.core.compiler.IProblem;
@@ -699,6 +703,23 @@
 		return stubTypeContext;
 	}
 
+	public static StubTypeContext createAnnotationStubTypeContext(/*@NonNull*/ IProject project) {
+		try {
+			for (IPackageFragmentRoot root : JavaCore.create(project).getPackageFragmentRoots()) {
+				if (!root.isReadOnly()) {
+					IPackageFragment packageFragment= root.getPackageFragment(""); //$NON-NLS-1$
+					String prolog= "abstract class __X__ {\n\tabstract @"; //$NON-NLS-1$
+					String epilog= " __X__ dummy();\n} "; //$NON-NLS-1$
+					ICompilationUnit cu= packageFragment.getCompilationUnit(JavaTypeCompletionProcessor.DUMMY_CU_NAME);
+					return new StubTypeContext(cu, prolog, epilog);
+				}
+			}
+		} catch (JavaModelException e) {
+			// fall through
+		}
+		return new StubTypeContext(null, null, null);
+	}
+
 	public static Type parseSuperClass(String superClass) {
 		return parseSuperType(superClass, false);
 	}
diff --git a/org.eclipse.jdt.ui/icons/full/obj16/blank.png b/org.eclipse.jdt.ui/icons/full/obj16/blank.png
new file mode 100644
index 0000000..c9cd48c
--- /dev/null
+++ b/org.eclipse.jdt.ui/icons/full/obj16/blank.png
Binary files differ
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java
index c02faed..5a6a143 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java
@@ -175,6 +175,8 @@
 
 	public static final String IMG_CONFIGURE_PROBLEM_SEVERITIES= NAME_PREFIX + "configure_problem_severity.png"; //$NON-NLS-1$
 
+	public static final String IMG_BLANK= NAME_PREFIX + "blank.png"; //$NON-NLS-1$
+
 	/*
 	 * Set of predefined Image Descriptors.
 	 */
@@ -478,6 +480,7 @@
 		createManagedFromKey(T_OBJ, IMG_OBJS_ERROR_ALT);
 		createManagedFromKey(T_OBJ, IMG_OBJS_WARNING_ALT);
 		createManagedFromKey(T_OBJ, IMG_OBJS_INFO_ALT);
+		createManagedFromKey(T_OBJ, IMG_BLANK);
 	}
 
 	private static final class CachedImageDescriptor extends ImageDescriptor {
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java
index 4dce36a..6870118 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -383,14 +383,21 @@
 	public static String ProblemSeveritiesConfigurationBlock_needsbuild_title;
 	public static String ProblemSeveritiesConfigurationBlock_needsfullbuild_message;
 	public static String ProblemSeveritiesConfigurationBlock_needsprojectbuild_message;
-	public static String NullAnnotationsConfigurationDialog_nonnull_annotation_label;
+	public static String NullAnnotationsConfigurationDialog_nonnull_annotations_label;
+	public static String NullAnnotationsConfigurationDialog_nonnull_annotations_description;
 	public static String ProblemSeveritiesConfigurationBlock_missing_nonnull_by_default_annotation;
 	public static String NullAnnotationsConfigurationDialog_nonnullbydefault_annotation_error;
-	public static String NullAnnotationsConfigurationDialog_nonnullbydefault_annotation_label;
-	public static String NullAnnotationsConfigurationDialog_nonull_annotation_error;
+	public static String NullAnnotationsConfigurationDialog_nonnullbydefault_annotations_label;
+	public static String NullAnnotationsConfigurationDialog_nonnullbydefault_annotations_description;
+	public static String NullAnnotationsConfigurationDialog_nonnull_annotation_error;
 	public static String NullAnnotationsConfigurationDialog_null_annotations_description;
 	public static String NullAnnotationsConfigurationDialog_nullable_annotation_error;
-	public static String NullAnnotationsConfigurationDialog_nullable_annotation_label;
+	public static String NullAnnotationsConfigurationDialog_nullable_annotations_label;
+	public static String NullAnnotationsConfigurationDialog_nullable_annotations_description;
+	public static String NullAnnotationsConfigurationDialog_add_button;
+	public static String NullAnnotationsConfigurationDialog_notFound_info;
+	public static String NullAnnotationsConfigurationDialog_primary_label;
+	public static String NullAnnotationsConfigurationDialog_secondary_label;
 	public static String ProblemSeveritiesConfigurationBlock_common_description;
 	public static String ProblemSeveritiesConfigurationBlock_pb_unavoidable_generic_type_problems;
 	public static String ProblemSeveritiesConfigurationBlock_pb_unsafe_type_op_label;
@@ -764,11 +771,6 @@
 	}
 
 	public static String NameConventionConfigurationBlock_use_override_annotation_label;
-	public static String NullAnnotationsConfigurationDialog_browse_title;
-	public static String NullAnnotationsConfigurationDialog_browse1;
-	public static String NullAnnotationsConfigurationDialog_browse2;
-	public static String NullAnnotationsConfigurationDialog_browse3;
-	public static String NullAnnotationsConfigurationDialog_choose_annotation;
 	public static String NullAnnotationsConfigurationDialog_error_message;
 	public static String NullAnnotationsConfigurationDialog_error_title;
 	public static String NullAnnotationsConfigurationDialog_restore_defaults;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties
index 5f756e9..cb351ff 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2015 IBM Corporation and others.
+# Copyright (c) 2000, 2016 IBM Corporation and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License v1.0
 # which accompanies this distribution, and is available at
@@ -403,14 +403,23 @@
 ProblemSeveritiesConfigurationBlock_needsbuild_title=Error/Warning Settings Changed
 ProblemSeveritiesConfigurationBlock_needsfullbuild_message=The Error/Warning settings have changed. A full rebuild is required for changes to take effect. Do the full build now?
 ProblemSeveritiesConfigurationBlock_needsprojectbuild_message=The Error/Warning settings have changed. A rebuild of the project is required for changes to take effect. Build the project now?
-NullAnnotationsConfigurationDialog_nonnull_annotation_label='N&onNull' annotation:
+NullAnnotationsConfigurationDialog_nonnull_annotations_label='N&onNull' annotations:
+NullAnnotationsConfigurationDialog_nonnull_annotations_description=Elements annotated with '@NonNull' must never be null.
 ProblemSeveritiesConfigurationBlock_missing_nonnull_by_default_annotation=Missing '@NonNullByDefault' annotation on package:
 NullAnnotationsConfigurationDialog_nonnullbydefault_annotation_error='NonNullByDefault' annotation must be a fully-qualified type name
-NullAnnotationsConfigurationDialog_nonnullbydefault_annotation_label='NonN&ullByDefault' annotation:
-NullAnnotationsConfigurationDialog_nonull_annotation_error='NonNull' annotation must be a fully-qualified type name
-NullAnnotationsConfigurationDialog_null_annotations_description=Enter custom annotation names for null specifications. Elements annotated with the '@Nullable' annotation can be null. Elements annotated with '@NonNull' must never be null. The '@NonNullByDefault' annotation sets 'non-null' as default for all elements in a package, type, or method.
+NullAnnotationsConfigurationDialog_nonnullbydefault_annotations_label='NonN&ullByDefault' annotations:
+NullAnnotationsConfigurationDialog_nonnullbydefault_annotations_description=The '@NonNullByDefault' annotation sets 'non-null' as default for all elements in a package, type, or method. \
+When using Eclipse's default '@NonNullByDefault' annotation, an optional annotation argument is evaluated, allowing to cancel or fine-tune the 'non-null' default.
+NullAnnotationsConfigurationDialog_nonnull_annotation_error='NonNull' annotation must be a fully-qualified type name
+NullAnnotationsConfigurationDialog_null_annotations_description=Enter custom annotation names for null specifications.\n\
+Primary annotations are for active use in source and class files, whereas secondary annotations are intended only for interpreting API of third-party libraries.
 NullAnnotationsConfigurationDialog_nullable_annotation_error='Nullable' annotation must be a fully-qualified type name
-NullAnnotationsConfigurationDialog_nullable_annotation_label='&Nullable' annotation:
+NullAnnotationsConfigurationDialog_nullable_annotations_label='&Nullable' annotations:
+NullAnnotationsConfigurationDialog_nullable_annotations_description=Elements annotated with the '@Nullable' annotation can be null.
+NullAnnotationsConfigurationDialog_add_button=Add
+NullAnnotationsConfigurationDialog_notFound_info=Annotation type {0} could not be found
+NullAnnotationsConfigurationDialog_primary_label=Primary annotation:
+NullAnnotationsConfigurationDialog_secondary_label=Secondary annotations:
 
 ProblemSeveritiesConfigurationBlock_enable_syntactic_null_analysis_for_fields=Enable syntactic null analysis for fields
 ProblemSeveritiesConfigurationBlock_inherit_null_annotations=Inherit null annotations
@@ -942,11 +951,6 @@
 NativeLibrariesPropertyPage_locationPath_none=(none)
 NativeLibrariesPropertyPage_not_supported=The current class path entry belongs to container ''{0}'' which does not support the attachment of native libraries to its entries.
 NativeLibrariesPropertyPage_read_only=The current class path entry belongs to container ''{0}'' which does not allow user modifications to native libraries on its entries.
-NullAnnotationsConfigurationDialog_browse_title=Annotation Selection
-NullAnnotationsConfigurationDialog_browse1=&Browse...
-NullAnnotationsConfigurationDialog_browse2=B&rowse...
-NullAnnotationsConfigurationDialog_browse3=Bro&wse...
-NullAnnotationsConfigurationDialog_choose_annotation=&Choose annotation name:
 NullAnnotationsConfigurationDialog_error_message=A problem occurred while collecting types. See the error log for details.
 NullAnnotationsConfigurationDialog_error_title=Annotation Selection
 NullAnnotationsConfigurationDialog_restore_defaults=Restore &Defaults
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ProblemSeveritiesConfigurationBlock.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ProblemSeveritiesConfigurationBlock.java
index dc83811..2bef36b 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ProblemSeveritiesConfigurationBlock.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ProblemSeveritiesConfigurationBlock.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,16 +13,29 @@
 package org.eclipse.jdt.internal.ui.preferences;
 
 import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.equinox.bidi.StructuredTextTypeHandlerFactory;
+import org.eclipse.osgi.util.NLS;
 
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Item;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.swt.widgets.Text;
@@ -32,158 +45,462 @@
 
 import org.eclipse.core.resources.IProject;
 
+import org.eclipse.jface.contentassist.SubjectControlContentAssistant;
 import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.dialogs.IDialogSettings;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.dialogs.StatusDialog;
 import org.eclipse.jface.layout.PixelConverter;
-import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.BidiUtils;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.jface.window.Window;
 
 import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.dialogs.SelectionDialog;
+import org.eclipse.ui.contentassist.ContentAssistHandler;
 import org.eclipse.ui.forms.widgets.ExpandableComposite;
 import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
 
-import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaConventions;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchEngine;
 
-import org.eclipse.jdt.ui.IJavaElementSearchConstants;
-import org.eclipse.jdt.ui.JavaUI;
+import org.eclipse.jdt.internal.corext.refactoring.StubTypeContext;
+import org.eclipse.jdt.internal.corext.refactoring.TypeContextChecker;
 
 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
 import org.eclipse.jdt.internal.ui.JavaPlugin;
+import org.eclipse.jdt.internal.ui.JavaPluginImages;
 import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
 import org.eclipse.jdt.internal.ui.dialogs.StatusUtil;
+import org.eclipse.jdt.internal.ui.dialogs.TableTextCellEditor;
 import org.eclipse.jdt.internal.ui.dialogs.TextFieldNavigationHandler;
-import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext;
+import org.eclipse.jdt.internal.ui.refactoring.contentassist.CompletionContextRequestor;
+import org.eclipse.jdt.internal.ui.refactoring.contentassist.ControlContentAssistHelper;
+import org.eclipse.jdt.internal.ui.refactoring.contentassist.JavaTypeCompletionProcessor;
 import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
+import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
 import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener;
-import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
-import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
-import org.eclipse.jdt.internal.ui.wizards.dialogfields.IStringButtonAdapter;
+import org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter;
 import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
-import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringButtonDialogField;
+import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField;
+import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringDialogField;
 
 
 public class ProblemSeveritiesConfigurationBlock extends OptionsConfigurationBlock {
 
+	private interface IAnnotationDialogField {
+		String getErrorMessage();
+		void setStatus(NullAnnotationsConfigurationDialog.AnnotationWrapper element, IStatus newStatus);
+	}
+
 	private class NullAnnotationsConfigurationDialog extends StatusDialog {
-		
-		private class StringButtonAdapter implements IDialogFieldListener, IStringButtonAdapter {
+
+		private static final String COLUMN_ANNOTATION= "annotation"; //$NON-NLS-1$
+		private static final String EMPTY_STRING= ""; //$NON-NLS-1$
+
+		private class AnnotationDialogField extends StringDialogField implements IAnnotationDialogField {
+			
+			final String fErrorMessage;
+			IStatus fStatus;
+			
+			public AnnotationDialogField(String errorMessage) {
+				fErrorMessage= errorMessage;
+				fStatus= new StatusInfo();
+			}
 			@Override
-			public void dialogFieldChanged(DialogField field) {
-				doValidation((StringButtonDialogField) field);
+			public String getText() {
+				return super.getText().trim();
+			}
+			@Override
+			public String getErrorMessage() {
+				return fErrorMessage;
+			}
+			public IStatus getStatus() {
+				return fStatus;
+			}
+			@Override
+			public void setStatus(AnnotationWrapper element, IStatus newStatus) {
+				fStatus= newStatus;
+			}
+			IStatus doValidation() {
+				return NullAnnotationsConfigurationDialog.this.doValidation(this, null, getText(), true);
+			}
+		}
+
+		private class AnnotationWrapper { // mimic a mutable string
+			public String annotationName;
+			public IStatus status; // null means: no status computed, yet.
+			
+			public AnnotationWrapper(String annotationName) {
+				this.annotationName= annotationName;
+			}
+		}
+
+		private class AnnotationListDialogField extends ListDialogField<AnnotationWrapper> implements IAnnotationDialogField {
+
+			final String fErrorMessage;
+
+			public AnnotationListDialogField(IListAdapter<AnnotationWrapper> adapter, String[] buttonLabels, ILabelProvider lprovider, String errorMessage) {
+				super(adapter, buttonLabels, lprovider);
+				fErrorMessage= errorMessage;
+			}
+
+			public void addElementsFromCommaSeparatedList(String value) {
+				value= value.trim();
+				if (value.isEmpty())
+					return;
+				String[] strings= value.split(","); //$NON-NLS-1$
+				for (int i= 0; i < strings.length; i++)
+					addElement(new AnnotationWrapper(strings[i].trim()));
+			}
+
+			public String getCommaSeparatedElements() {
+				List<AnnotationWrapper> elements= getElements();
+				if (elements.isEmpty()) return EMPTY_STRING;
+				StringBuilder buf= new StringBuilder();
+				for (int i= 0; i < elements.size(); i++) {
+					String annotationName= elements.get(i).annotationName;
+					if (annotationName.isEmpty())
+						continue;
+					if (i > 0) buf.append(',');
+					buf.append(annotationName);
+				}
+				return buf.toString();
 			}
 
 			@Override
-			public void changeControlPressed(DialogField field) {
-				doBrowseTypes((StringButtonDialogField) field);
+			public void elementChanged(AnnotationWrapper element) throws IllegalArgumentException {
+				super.elementChanged(element);
+				NullAnnotationsConfigurationDialog.this.doValidation(this, element, element.annotationName, false);
+			}
+			@Override
+			public String getErrorMessage() {
+				return fErrorMessage;
+			}
+			public IStatus getMostSevereStatus() {
+				List<AnnotationWrapper> elements= getElements();
+				if (elements.isEmpty())
+					return new StatusInfo();
+				IStatus[] all= new IStatus[elements.size()];
+				for (int i= 0; i < elements.size(); i++) {
+					all[i]= elements.get(i).status;
+					if (all[i] == null)
+						all[i]= new StatusInfo();
+				}
+				return StatusUtil.getMostSevere(all);
+			}
+			@Override
+			public void setStatus(AnnotationWrapper element, IStatus newStatus) {
+				element.status= newStatus;
+			}
+		}
+	
+		private class FieldListener implements ModifyListener {
+			AnnotationDialogField fField;
+			FieldListener(AnnotationDialogField field) {
+				fField= field;
+			}
+
+			@Override
+			public void modifyText(ModifyEvent e) {
+				fField.doValidation();
+			}
+		}
+
+		private class AnnotationCompletionContextRequestor extends CompletionContextRequestor {
+			@Override
+			public StubTypeContext getStubTypeContext() {
+				return TypeContextChecker.createAnnotationStubTypeContext(fProject);
+			}
+		}
+
+		private class AnnotationListAdapter implements IListAdapter<AnnotationWrapper> {
+
+			@Override
+			public void customButtonPressed(ListDialogField<AnnotationWrapper> field, int index) {
+				if (index == 0) { // "Add"
+					AnnotationWrapper newElement= new AnnotationWrapper(EMPTY_STRING);
+					field.addElement(newElement);
+					field.editElement(newElement);
+				}
+			}
+
+			@Override
+			public void selectionChanged(ListDialogField<AnnotationWrapper> field) {
+				// nothing
+			}
+
+			@Override
+			public void doubleClicked(ListDialogField<AnnotationWrapper> field) {
+				// nothing
+			}
+		}
+
+		private class AnnotationListLabelProvider extends LabelProvider {
+
+			AnnotationListDialogField fField;
+			
+			void setDialogField(AnnotationListDialogField field) {
+				fField= field;
+			}
+			
+			@Override
+			public String getText(Object element) {
+				return BasicElementLabels.getJavaElementName(((AnnotationWrapper) element).annotationName);
+			}
+			
+			@Override
+			public Image getImage(Object element) {
+				if (element instanceof AnnotationWrapper) {
+					AnnotationWrapper annotationWrapper= (AnnotationWrapper) element;
+					IStatus status= annotationWrapper.status;
+					if (status == null) {
+						status= validateNullnessAnnotation(annotationWrapper.annotationName, fField.getErrorMessage(), false);
+						annotationWrapper.status= status;
+					}
+					switch (status.getSeverity()) {
+						case IStatus.INFO:
+							return JavaPluginImages.get(JavaPluginImages.IMG_OBJS_REFACTORING_INFO);
+						case IStatus.ERROR:
+							return JavaPluginImages.get(JavaPluginImages.IMG_OBJS_REFACTORING_ERROR);
+						default:
+							// fall through
+					}
+				}
+				return JavaPluginImages.get(JavaPluginImages.IMG_BLANK);
 			}
 		}
 
 		private static final int RESTORE_DEFAULTS_BUTTON_ID= IDialogConstants.CLIENT_ID + 1;
 		
 		
-		private StringButtonDialogField fNullableAnnotationDialogField;
-		private StringButtonDialogField fNonNullAnnotationDialogField;
-		private StringButtonDialogField fNonNullByDefaultAnnotationDialogField;
-		private IStatus fNullableStatus, fNonNullStatus, fNonNullByDefaultStatus;
+		private AnnotationDialogField fNullableAnnotationDialogField;
+		private AnnotationDialogField fNonNullAnnotationDialogField;
+		private AnnotationDialogField fNonNullByDefaultAnnotationDialogField;
+		private AnnotationListDialogField fOtherNullableAnnotationsDialogField;
+		private AnnotationListDialogField fOtherNonNullAnnotationsDialogField;
+		private AnnotationListDialogField fOtherNonNullByDefaultAnnotationsDialogField;
 
 		private NullAnnotationsConfigurationDialog() {
 			super(ProblemSeveritiesConfigurationBlock.this.getShell());
 			
 			setTitle(PreferencesMessages.NullAnnotationsConfigurationDialog_title);
-			
-			fNullableStatus= new StatusInfo();
-			fNonNullStatus= new StatusInfo();
-			fNonNullByDefaultStatus= new StatusInfo();
-			
-			StringButtonAdapter adapter= new StringButtonAdapter();
 
-			fNullableAnnotationDialogField= new StringButtonDialogField(adapter);
-			fNullableAnnotationDialogField.setLabelText(PreferencesMessages.NullAnnotationsConfigurationDialog_nullable_annotation_label);
-			fNullableAnnotationDialogField.setButtonLabel(PreferencesMessages.NullAnnotationsConfigurationDialog_browse1);
-			fNullableAnnotationDialogField.setDialogFieldListener(adapter);
-			fNullableAnnotationDialogField.setText(getValue(PREF_NULLABLE_ANNOTATION_NAME));
+			String errorMessage= PreferencesMessages.NullAnnotationsConfigurationDialog_nullable_annotation_error;
+			fNullableAnnotationDialogField= createAnnotationDialogField(PREF_NULLABLE_ANNOTATION_NAME, errorMessage);
+			fOtherNullableAnnotationsDialogField= createAnnotationListDialogField(PREF_NULLABLE_ANNOTATION_SECONDARY_NAMES, errorMessage);
 			
-			fNonNullAnnotationDialogField= new StringButtonDialogField(adapter);
-			fNonNullAnnotationDialogField.setLabelText(PreferencesMessages.NullAnnotationsConfigurationDialog_nonnull_annotation_label);
-			fNonNullAnnotationDialogField.setButtonLabel(PreferencesMessages.NullAnnotationsConfigurationDialog_browse2);
-			fNonNullAnnotationDialogField.setDialogFieldListener(adapter);
-			fNonNullAnnotationDialogField.setText(getValue(PREF_NONNULL_ANNOTATION_NAME));
+			errorMessage= PreferencesMessages.NullAnnotationsConfigurationDialog_nonnull_annotation_error;
+			fNonNullAnnotationDialogField= createAnnotationDialogField(PREF_NONNULL_ANNOTATION_NAME, errorMessage);
+			fOtherNonNullAnnotationsDialogField= createAnnotationListDialogField(PREF_NONNULL_ANNOTATION_SECONDARY_NAMES, errorMessage);
 			
-			fNonNullByDefaultAnnotationDialogField= new StringButtonDialogField(adapter);
-			fNonNullByDefaultAnnotationDialogField.setLabelText(PreferencesMessages.NullAnnotationsConfigurationDialog_nonnullbydefault_annotation_label);
-			fNonNullByDefaultAnnotationDialogField.setButtonLabel(PreferencesMessages.NullAnnotationsConfigurationDialog_browse3);
-			fNonNullByDefaultAnnotationDialogField.setDialogFieldListener(adapter);
-			fNonNullByDefaultAnnotationDialogField.setText(getValue(PREF_NONNULL_BY_DEFAULT_ANNOTATION_NAME));
+			errorMessage= PreferencesMessages.NullAnnotationsConfigurationDialog_nonnullbydefault_annotation_error;
+			fNonNullByDefaultAnnotationDialogField= createAnnotationDialogField(PREF_NONNULL_BY_DEFAULT_ANNOTATION_NAME, errorMessage);
+			fOtherNonNullByDefaultAnnotationsDialogField= createAnnotationListDialogField(PREF_NONNULL_BY_DEFAULT_ANNOTATION_SECONDARY_NAMES, errorMessage);
 		}
-		
+
+		private AnnotationDialogField createAnnotationDialogField(Key key, String errorMessage) {
+			AnnotationDialogField field= new AnnotationDialogField(errorMessage);
+			field.setLabelText(PreferencesMessages.NullAnnotationsConfigurationDialog_primary_label);
+			field.setText(getValue(key));
+			return field;
+		}
+
+		private AnnotationListDialogField createAnnotationListDialogField(Key key, String errorMessage) {
+			String[] buttons= new String[] { PreferencesMessages.NullAnnotationsConfigurationDialog_add_button };
+			AnnotationListLabelProvider annotationLabelProvider= new AnnotationListLabelProvider();
+			AnnotationListDialogField field= new AnnotationListDialogField(new AnnotationListAdapter(), buttons, annotationLabelProvider, errorMessage);
+			field.setLabelText(PreferencesMessages.NullAnnotationsConfigurationDialog_secondary_label);
+			field.setTableColumns(new ListDialogField.ColumnsDescription(1, false));
+			field.addElementsFromCommaSeparatedList(getValue(key));
+			annotationLabelProvider.setDialogField(field);
+			return field;
+		}
+
 		@Override
 		protected Control createDialogArea(Composite parent) {
 			Composite composite= (Composite) super.createDialogArea(parent);
 			initializeDialogUnits(parent);
 
 			GridLayout layout= (GridLayout) composite.getLayout();
-			layout.numColumns= 3;
+			layout.numColumns= 1;
 			
-			int fieldWidthHint= convertWidthInCharsToPixels(60);
+			int fieldWidthHint= convertWidthInCharsToPixels(90); // heuristic to match the default size of the dialog
 			
 			Label intro= new Label(composite, SWT.WRAP);
 			intro.setText(PreferencesMessages.NullAnnotationsConfigurationDialog_null_annotations_description);
 	    	intro.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false, layout.numColumns, 1));
 			LayoutUtil.setWidthHint(intro, fieldWidthHint);
 	    	
-			fNullableAnnotationDialogField.doFillIntoGrid(composite, 3);
-			Text text= fNullableAnnotationDialogField.getTextControl(null);
-			LayoutUtil.setWidthHint(text, fieldWidthHint);
-			TextFieldNavigationHandler.install(text);
+			String[] texts= { PreferencesMessages.NullAnnotationsConfigurationDialog_nullable_annotations_label,
+					PreferencesMessages.NullAnnotationsConfigurationDialog_nullable_annotations_description };
+			createNullAnnotationGroup(fNullableAnnotationDialogField, fOtherNullableAnnotationsDialogField, composite, texts, fieldWidthHint);
 
-			fNonNullAnnotationDialogField.doFillIntoGrid(composite, 3);
-			TextFieldNavigationHandler.install(fNonNullAnnotationDialogField.getTextControl(null));
-			
-			fNonNullByDefaultAnnotationDialogField.doFillIntoGrid(composite, 3);
-			TextFieldNavigationHandler.install(fNonNullByDefaultAnnotationDialogField.getTextControl(null));
-			
+			texts= new String[] { PreferencesMessages.NullAnnotationsConfigurationDialog_nonnull_annotations_label,
+					PreferencesMessages.NullAnnotationsConfigurationDialog_nonnull_annotations_description };
+			createNullAnnotationGroup(fNonNullAnnotationDialogField, fOtherNonNullAnnotationsDialogField, composite, texts, fieldWidthHint);
+
+
+			texts= new String[] { PreferencesMessages.NullAnnotationsConfigurationDialog_nonnullbydefault_annotations_label,
+					PreferencesMessages.NullAnnotationsConfigurationDialog_nonnullbydefault_annotations_description };
+			createNullAnnotationGroup(fNonNullByDefaultAnnotationDialogField, fOtherNonNullByDefaultAnnotationsDialogField, composite, texts, fieldWidthHint);
+
 			fNullableAnnotationDialogField.postSetFocusOnDialogField(parent.getDisplay());
 
 			applyDialogFont(composite);
 			return composite;
 		}
-		
-		private void doBrowseTypes(StringButtonDialogField dialogField) {
-			IRunnableContext context= new BusyIndicatorRunnableContext();
-			IJavaSearchScope scope= SearchEngine.createWorkspaceScope();
-			int style= IJavaElementSearchConstants.CONSIDER_ANNOTATION_TYPES;
-			try {
-				SelectionDialog dialog= JavaUI.createTypeDialog(getShell(), context, scope, style, false, dialogField.getText());
-				dialog.setTitle(PreferencesMessages.NullAnnotationsConfigurationDialog_browse_title);
-				dialog.setMessage(PreferencesMessages.NullAnnotationsConfigurationDialog_choose_annotation);
-				if (dialog.open() == Window.OK) {
-					IType res= (IType) dialog.getResult()[0];
-					dialogField.setText(res.getFullyQualifiedName('.'));
+
+		private void createNullAnnotationGroup(AnnotationDialogField primaryField, final AnnotationListDialogField secondaryList, Composite parent, String[] texts, int fieldWidthHint) {
+			Group group= new Group(parent, SWT.NONE);
+			GridLayout layout= new GridLayout(3, false);
+			layout.marginLeft= convertWidthInCharsToPixels(2);
+			GridData groupData= new GridData(SWT.FILL, SWT.FILL, true, true);
+
+			// compensate different height of intro texts when suggesting height of the group:
+			GC gc= new GC(parent);
+			gc.setFont(JFaceResources.getDialogFont());
+			Point size= gc.stringExtent(texts[1]);
+			int lines= (size.x / fieldWidthHint) + 1;
+			gc.dispose();
+			groupData.heightHint= convertHeightInCharsToPixels(8+lines);
+			
+			group.setLayoutData(groupData);
+			group.setLayout(layout);
+			group.setText(texts[0]);
+
+			Label intro= new Label(group, SWT.WRAP);
+			intro.setText(texts[1]);
+			intro.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, layout.numColumns, 1));
+			LayoutUtil.setWidthHint(intro, 1); // force text wrapping
+
+			
+			primaryField.doFillIntoGrid(group, 2);
+			addSpacer(group); // button column is empty for the primary field
+
+			Text text= primaryField.getTextControl(null);
+			((GridData)text.getLayoutData()).grabExcessHorizontalSpace= true;
+			text.addModifyListener(new FieldListener(primaryField));
+			TextFieldNavigationHandler.install(text);
+			BidiUtils.applyBidiProcessing(text, StructuredTextTypeHandlerFactory.JAVA);
+
+			if (fProject != null) {
+				JavaTypeCompletionProcessor annotationCompletionProcessor= new JavaTypeCompletionProcessor(false, false, true);
+				annotationCompletionProcessor.setCompletionContextRequestor(new AnnotationCompletionContextRequestor());
+				ControlContentAssistHelper.createTextContentAssistant(text, annotationCompletionProcessor);
+			}
+			
+			
+			secondaryList.doFillIntoGrid(group, 3);
+			final TableViewer tableViewer= secondaryList.getTableViewer();
+			tableViewer.setColumnProperties(new String[] {COLUMN_ANNOTATION});
+			TableTextCellEditor cellEditor= new TableTextCellEditor(tableViewer, 0) {
+				@Override
+				protected Control createControl(Composite parent2) {
+					Control control= super.createControl(parent2);
+					BidiUtils.applyBidiProcessing(text, StructuredTextTypeHandlerFactory.JAVA);
+					return control;
 				}
-			} catch (JavaModelException e) {
-				ExceptionHandler.handle(e, getShell(), PreferencesMessages.NullAnnotationsConfigurationDialog_error_title, PreferencesMessages.NullAnnotationsConfigurationDialog_error_message);
+
+				@Override
+			    protected void keyReleaseOccured(KeyEvent event) {
+					if (event.keyCode == SWT.F2 && event.stateMask == 0) {
+						tableViewer.refresh(); // ensure icon is updated on F2
+					}
+			    	super.keyReleaseOccured(event);
+			    }
+			};
+			Text cellEditorText= cellEditor.getText();
+			TextFieldNavigationHandler.install(cellEditorText);
+			if (fProject != null) {
+				JavaTypeCompletionProcessor annotationCompletionProcessor= new JavaTypeCompletionProcessor(false, false, true);
+				annotationCompletionProcessor.setCompletionContextRequestor(new AnnotationCompletionContextRequestor());
+				SubjectControlContentAssistant contentAssistant= ControlContentAssistHelper.createJavaContentAssistant(annotationCompletionProcessor);
+				ContentAssistHandler.createHandlerForText(cellEditorText, contentAssistant);
+				cellEditor.setContentAssistant(contentAssistant);
+			}
+
+			tableViewer.setCellEditors(new CellEditor[] { cellEditor });
+			tableViewer.setCellModifier(new ICellModifier() {
+				@Override
+				public void modify(Object element, String property, Object value) {
+					if (element instanceof Item)
+						element= ((Item) element).getData();
+
+					AnnotationWrapper annotationWrapper= (AnnotationWrapper) element;
+					annotationWrapper.annotationName= ((String) value).trim();
+					secondaryList.elementChanged(annotationWrapper);
+				}
+				@Override
+				public Object getValue(Object element, String property) {
+					return ((AnnotationWrapper) element).annotationName;
+				}
+				@Override
+				public boolean canModify(Object element, String property) {
+					return true;
+				}
+			});
+			tableViewer.getTable().addKeyListener(new KeyAdapter() {
+				@Override
+				public void keyPressed(KeyEvent event) {
+					if (event.keyCode == SWT.F2 && event.stateMask == 0) {
+						ISelection selection= tableViewer.getSelection();
+						if (! (selection instanceof IStructuredSelection))
+							return;
+						IStructuredSelection structuredSelection= (IStructuredSelection) selection;
+						if (!structuredSelection.isEmpty())
+							tableViewer.editElement(structuredSelection.getFirstElement(), 0);
+					}
+				}
+			});
+		}
+
+		private Label addSpacer(Group group) {
+			return new Label(group,  SWT.NONE);
+		}
+
+		@Override
+		public void create() {
+			super.create(); // cannot show error status before this super call
+			StringDialogField firstErrorField= null;
+			IStatus firstError= null;
+			AnnotationDialogField[] primaryFields= { fNullableAnnotationDialogField, fNonNullAnnotationDialogField, fNonNullByDefaultAnnotationDialogField };
+			for (AnnotationDialogField field : primaryFields) {
+				IStatus status= field.doValidation();
+				if (status.getSeverity() == IStatus.ERROR && firstError == null) {
+					firstErrorField= field;
+					firstError= status;
+				}
+			}
+			if (firstErrorField != null && firstError != null) {
+				updateStatus(firstError);
+				firstErrorField.postSetFocusOnDialogField(dialogArea.getDisplay());
 			}
 		}
-		
-		private void doValidation(StringButtonDialogField dialogField) {
-			String newValue= dialogField.getText();
-			if (fNullableAnnotationDialogField.equals(dialogField)) {
-				fNullableStatus= validateNullnessAnnotation(newValue, PreferencesMessages.NullAnnotationsConfigurationDialog_nullable_annotation_error);
-			} else if (fNonNullAnnotationDialogField.equals(dialogField)) {
-				fNonNullStatus= validateNullnessAnnotation(newValue, PreferencesMessages.NullAnnotationsConfigurationDialog_nonull_annotation_error);
-			} else if (fNonNullByDefaultAnnotationDialogField.equals(dialogField)) {
-				fNonNullByDefaultStatus= validateNullnessAnnotation(newValue, PreferencesMessages.NullAnnotationsConfigurationDialog_nonnullbydefault_annotation_error);
+
+		private IStatus doValidation(IAnnotationDialogField dialogField, AnnotationWrapper element, String newValue, boolean isTypeMandatory) {
+			IStatus fieldStatus= validateNullnessAnnotation(newValue, dialogField.getErrorMessage(), isTypeMandatory);
+			if (fieldStatus != null) {
+				dialogField.setStatus(element, fieldStatus);
+
+				// compute most severe among all known statuses, preferring fieldStatus then first-found if equal severities:
+				IStatus mostSevereStatus= StatusUtil.getMoreSevere(fNullableAnnotationDialogField.getStatus(), fieldStatus);
+				mostSevereStatus= StatusUtil.getMoreSevere(fNonNullAnnotationDialogField.getStatus(), mostSevereStatus);
+				mostSevereStatus= StatusUtil.getMoreSevere(fNonNullByDefaultAnnotationDialogField.getStatus(), mostSevereStatus);
+				mostSevereStatus= StatusUtil.getMoreSevere(fOtherNullableAnnotationsDialogField.getMostSevereStatus(), mostSevereStatus);
+				mostSevereStatus= StatusUtil.getMoreSevere(fOtherNonNullAnnotationsDialogField.getMostSevereStatus(), mostSevereStatus);
+				mostSevereStatus= StatusUtil.getMoreSevere(fOtherNonNullByDefaultAnnotationsDialogField.getMostSevereStatus(), mostSevereStatus);
+				updateStatus(mostSevereStatus);
+				return fieldStatus;
 			}
-			IStatus status= StatusUtil.getMostSevere(new IStatus[] { fNullableStatus, fNonNullStatus, fNonNullByDefaultStatus });
-			updateStatus(status);
+			return new StatusInfo();
 		}
 
 		@Override
@@ -198,6 +515,9 @@
 				fNullableAnnotationDialogField.setText(NULL_ANNOTATIONS_DEFAULTS[0]);
 				fNonNullAnnotationDialogField.setText(NULL_ANNOTATIONS_DEFAULTS[1]);
 				fNonNullByDefaultAnnotationDialogField.setText(NULL_ANNOTATIONS_DEFAULTS[2]);
+				fOtherNullableAnnotationsDialogField.removeAllElements();
+				fOtherNonNullAnnotationsDialogField.removeAllElements();
+				fOtherNonNullByDefaultAnnotationsDialogField.removeAllElements();
 			} else {
 				super.buttonPressed(buttonId);
 			}
@@ -207,9 +527,13 @@
 			return new String[] {
 					fNullableAnnotationDialogField.getText(),
 					fNonNullAnnotationDialogField.getText(),
-					fNonNullByDefaultAnnotationDialogField.getText()
+					fNonNullByDefaultAnnotationDialogField.getText(),
+					fOtherNullableAnnotationsDialogField.getCommaSeparatedElements(),
+					fOtherNonNullAnnotationsDialogField.getCommaSeparatedElements(),
+					fOtherNonNullByDefaultAnnotationsDialogField.getCommaSeparatedElements()
 			};
 		}
+
 		@Override
 		protected boolean isResizable() {
 			return true;
@@ -289,6 +613,9 @@
 	private static final Key PREF_NULLABLE_ANNOTATION_NAME= getJDTCoreKey(JavaCore.COMPILER_NULLABLE_ANNOTATION_NAME);
 	private static final Key PREF_NONNULL_ANNOTATION_NAME= getJDTCoreKey(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME);
 	private static final Key PREF_NONNULL_BY_DEFAULT_ANNOTATION_NAME= getJDTCoreKey(JavaCore.COMPILER_NONNULL_BY_DEFAULT_ANNOTATION_NAME);
+	private static final Key PREF_NULLABLE_ANNOTATION_SECONDARY_NAMES= getJDTCoreKey(JavaCore.COMPILER_NULLABLE_ANNOTATION_SECONDARY_NAMES);
+	private static final Key PREF_NONNULL_ANNOTATION_SECONDARY_NAMES= getJDTCoreKey(JavaCore.COMPILER_NONNULL_ANNOTATION_SECONDARY_NAMES);
+	private static final Key PREF_NONNULL_BY_DEFAULT_ANNOTATION_SECONDARY_NAMES= getJDTCoreKey(JavaCore.COMPILER_NONNULL_BY_DEFAULT_ANNOTATION_SECONDARY_NAMES);
 	private static final String[] NULL_ANNOTATIONS_DEFAULTS= {
 		PREF_NULLABLE_ANNOTATION_NAME.getStoredValue(DefaultScope.INSTANCE, null),
 		PREF_NONNULL_ANNOTATION_NAME.getStoredValue(DefaultScope.INSTANCE, null),
@@ -385,8 +712,11 @@
 				PREF_ANNOTATION_NULL_ANALYSIS,
 				INTR_DEFAULT_NULL_ANNOTATIONS,
 				PREF_NULLABLE_ANNOTATION_NAME,
+				PREF_NULLABLE_ANNOTATION_SECONDARY_NAMES,
 				PREF_NONNULL_ANNOTATION_NAME,
+				PREF_NONNULL_ANNOTATION_SECONDARY_NAMES,
 				PREF_NONNULL_BY_DEFAULT_ANNOTATION_NAME,
+				PREF_NONNULL_BY_DEFAULT_ANNOTATION_SECONDARY_NAMES,
 				PREF_MISSING_NONNULL_BY_DEFAULT_ANNOTATION,
 				PREF_PB_NULL_SPECIFICATION_VIOLATION,
 				PREF_PB_POTENTIAL_NULL_ANNOTATION_INFERENCE_CONFLICT,
@@ -853,6 +1183,9 @@
 			setValue(PREF_NULLABLE_ANNOTATION_NAME, annotationNames[0]);
 			setValue(PREF_NONNULL_ANNOTATION_NAME, annotationNames[1]);
 			setValue(PREF_NONNULL_BY_DEFAULT_ANNOTATION_NAME, annotationNames[2]);
+			setValue(PREF_NULLABLE_ANNOTATION_SECONDARY_NAMES, annotationNames[3]);
+			setValue(PREF_NONNULL_ANNOTATION_SECONDARY_NAMES, annotationNames[4]);
+			setValue(PREF_NONNULL_BY_DEFAULT_ANNOTATION_SECONDARY_NAMES, annotationNames[5]);
 		}
 		updateNullAnnotationsSetting();
 	}
@@ -1022,11 +1355,26 @@
 		getCheckBox(PREF_PB_SYNTACTIC_NULL_ANLYSIS_FOR_FIELDS).setEnabled(enableAnnotationNullAnalysis);
 	}
 
-	private IStatus validateNullnessAnnotation(String value, String errorMessage) {
+	private IStatus validateNullnessAnnotation(String value, String errorMessage, boolean isTypeMandatory) {
 		StatusInfo status= new StatusInfo();
+		if (value.isEmpty() && !isTypeMandatory)
+			return status;
 		if (JavaConventions.validateJavaTypeName(value, JavaCore.VERSION_1_5, JavaCore.VERSION_1_5).matches(IStatus.ERROR)
-				|| value.indexOf('.') == -1)
+				|| value.indexOf('.') == -1) {
 			status.setError(errorMessage);
+		} else if (fProject != null) {
+			try {
+				if (JavaCore.create(fProject).findType(value) == null) {
+					String notFoundMessage= NLS.bind(PreferencesMessages.NullAnnotationsConfigurationDialog_notFound_info, value);
+					if (isTypeMandatory)
+						status.setError(notFoundMessage);
+					else
+						status.setInfo(notFoundMessage);
+				}
+			} catch (JavaModelException e) {
+				ExceptionHandler.handle(e, getShell(), PreferencesMessages.NullAnnotationsConfigurationDialog_error_title, PreferencesMessages.NullAnnotationsConfigurationDialog_error_message);
+			}
+		}
 		return status;
 	}