blob: 729311dfe4a85074bc14c3a6a06f2e06f37ae6da [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2011 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.jeview.views;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import org.eclipse.core.resources.IResource;
import org.eclipse.jdt.core.IAnnotatable;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJarEntryResource;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMemberValuePair;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IModularClassFile;
import org.eclipse.jdt.core.IOrdinaryClassFile;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IParent;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.JavaElementLabels;
public class JavaElement extends JEAttribute {
private static final long LABEL_OPTIONS= JavaElementLabels.F_APP_TYPE_SIGNATURE | JavaElementLabels.M_PARAMETER_TYPES | JavaElementLabels.M_APP_RETURNTYPE | JavaElementLabels.ALL_FULLY_QUALIFIED | JavaElementLabels.T_TYPE_PARAMETERS | JavaElementLabels.USE_RESOLVED;
private final JEAttribute fParent; //can be null
private final String fName; //can be null
private final IJavaElement fJavaElement; //can be null
public JavaElement(JEAttribute parent, String name, IJavaElement element) {
fParent= parent;
fName= name;
fJavaElement= element;
}
public JavaElement(JEAttribute parent, IJavaElement element) {
this(parent, null, element);
}
@Override
public JEAttribute getParent() {
return fParent;
}
public IJavaElement getJavaElement() {
return fJavaElement;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || !obj.getClass().equals(getClass())) {
return false;
}
JavaElement other= (JavaElement) obj;
if (fParent == null) {
if (other.fParent != null)
return false;
} else if (! fParent.equals(other.fParent)) {
return false;
}
if (fName == null) {
if (other.fName != null)
return false;
} else if (! fName.equals(other.fName)) {
return false;
}
if (fJavaElement == null) {
if (other.fJavaElement != null)
return false;
} else if (! fJavaElement.equals(other.fJavaElement)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return (fParent != null ? fParent.hashCode() : 0)
+ (fName != null ? fName.hashCode() : 0)
+ (fJavaElement != null ? fJavaElement.hashCode() : 0);
}
@Override
public Object getWrappedObject() {
return fJavaElement;
}
@Override
public String getLabel() {
StringBuilder sb= new StringBuilder();
if (fName != null)
sb.append(fName).append(": ");
if (fJavaElement == null) {
sb.append("java element: null");
} else {
String classname= fJavaElement.getClass().getName();
sb.append(classname.substring(classname.lastIndexOf('.') + 1)).append(": ");
sb.append(JavaElementLabels.getElementLabel(fJavaElement, LABEL_OPTIONS));
if (! fJavaElement.exists())
sb.append(" (does not exist)");
}
return sb.toString();
}
@Override
public JEAttribute[] getChildren() {
if (fJavaElement == null)
return EMPTY;
ArrayList<JEAttribute> result= new ArrayList<>();
if (fJavaElement instanceof IParent) {
addParentChildren(result, (IParent) fJavaElement);
}
addJavaElementChildren(result, fJavaElement);
if (fJavaElement instanceof IJavaModel)
addJavaModelChildren(result, (IJavaModel) fJavaElement);
if (fJavaElement instanceof IJavaProject)
addJavaProjectChildren(result, (IJavaProject) fJavaElement);
if (fJavaElement instanceof IPackageFragmentRoot)
addPackageFragmentRootChildren(result, (IPackageFragmentRoot) fJavaElement);
if (fJavaElement instanceof IPackageFragment)
addPackageFragmentChildren(result, (IPackageFragment) fJavaElement);
if (fJavaElement instanceof ITypeRoot)
addTypeRootChildren(result, (ITypeRoot) fJavaElement);
if (fJavaElement instanceof IOrdinaryClassFile)
addClassFileChildren(result, (IOrdinaryClassFile) fJavaElement);
if (fJavaElement instanceof IModularClassFile)
addModularClassFileChildren(result, (IModularClassFile) fJavaElement);
if (fJavaElement instanceof ICompilationUnit)
addCompilationUnitChildren(result, (ICompilationUnit) fJavaElement);
if (fJavaElement instanceof IType)
addTypeChildren(result, (IType) fJavaElement);
if (fJavaElement instanceof IMethod)
addMethodChildren(result, (IMethod) fJavaElement);
if (fJavaElement instanceof IMember)
addMemberChildren(result, (IMember) fJavaElement);
if (fJavaElement instanceof ITypeParameter)
addTypeParameterChildren(result, (ITypeParameter) fJavaElement);
if (fJavaElement instanceof ILocalVariable)
addLocalVariableChildren(result, (ILocalVariable) fJavaElement);
if (fJavaElement instanceof IAnnotation)
addAnnotationChildren(result, (IAnnotation) fJavaElement);
if (fJavaElement instanceof IAnnotatable)
addAnnotatableChildren(result, (IAnnotatable) fJavaElement);
return result.toArray(new JEAttribute[result.size()]);
}
private void addParentChildren(ArrayList<JEAttribute> result, final IParent parent) {
result.add(new JavaElementChildrenProperty(this, "CHILDREN") {
@Override
public JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, parent.getChildren());
}
});
}
private void addJavaElementChildren(ArrayList<JEAttribute> result, final IJavaElement javaElement) {
result.add(new JavaElement(this, "PARENT", javaElement.getParent()));
result.add(new JavaElement(this, "PRIMARY ELEMENT", javaElement.getPrimaryElement()));
result.add(new JavaElement(this, "JAVA MODEL", javaElement.getJavaModel()));
result.add(new JavaElement(this, "JAVA PROJECT", javaElement.getJavaProject()));
result.add(JEResource.create(this, "RESOURCE", javaElement.getResource()));
result.add(JEResource.compute(this, "CORRESPONDING RESOURCE", () -> javaElement.getCorrespondingResource()));
result.add(JEResource.compute(this, "UNDERLYING RESOURCE", () -> javaElement.getUnderlyingResource()));
}
private void addJavaModelChildren(ArrayList<JEAttribute> result, final IJavaModel javaModel) {
result.add(new JavaElementChildrenProperty(this, "JAVA PROJECTS") {
@Override
public JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, javaModel.getJavaProjects());
}
});
result.add(new JavaElementChildrenProperty(this, "NON JAVA RESOURCES") {
@Override
public JEAttribute[] computeChildren() throws JavaModelException {
return createResources(this, javaModel.getNonJavaResources());
}
});
}
private void addJavaProjectChildren(ArrayList<JEAttribute> result, final IJavaProject project) {
result.add(new JavaElementChildrenProperty(this, "ALL PACKAGE FRAGMENT ROOTS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, project.getAllPackageFragmentRoots());
}
});
result.add(new JavaElementChildrenProperty(this, "PACKAGE FRAGMENT ROOTS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, project.getPackageFragmentRoots());
}
});
result.add(new JavaElementChildrenProperty(this, "PACKAGE FRAGMENTS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, project.getPackageFragments());
}
});
result.add(new JavaElementChildrenProperty(this, "NON JAVA RESOURCES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createResources(this, project.getNonJavaResources());
}
});
result.add(JEResource.create(this, "PROJECT", project.getProject()));
result.add(new JavaElementChildrenProperty(this, "REQUIRED PROJECT NAMES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createStrings(this, project.getRequiredProjectNames());
}
});
result.add(new JavaElementChildrenProperty(this, "OPTIONS(FALSE)") {
@Override
protected JEAttribute[] computeChildren() {
return createOptions(this, project.getOptions(false));
}
});
result.add(new JavaElementChildrenProperty(this, "OPTIONS(TRUE)") {
@Override
protected JEAttribute[] computeChildren() {
return createOptions(this, project.getOptions(true));
}
});
result.add(new JavaElementChildrenProperty(this, "RAW CLASSPATH") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createCPEntries(this, project.getRawClasspath());
}
});
result.add(new JavaElementChildrenProperty(this, "REFERENCED CLASSPATH ENTRIES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createCPEntries(this, project.getReferencedClasspathEntries());
}
});
result.add(new JavaElementChildrenProperty(this, "RESOLVED CLASSPATH") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createCPEntries(this, project.getResolvedClasspath(false));
}
});
}
private void addPackageFragmentRootChildren(ArrayList<JEAttribute> result, final IPackageFragmentRoot packageFragmentRoot) {
result.add(new JavaElementChildrenProperty(this, "NON JAVA RESOURCES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createResources(this, packageFragmentRoot.getNonJavaResources());
}
});
result.add(JEClasspathEntry.compute(this, "RAW CLASSPATH ENTRY", () -> packageFragmentRoot.getRawClasspathEntry()));
result.add(JEClasspathEntry.compute(this, "RESOLVED CLASSPATH ENTRY", () -> packageFragmentRoot.getResolvedClasspathEntry()));
}
private void addPackageFragmentChildren(ArrayList<JEAttribute> result, final IPackageFragment packageFragment) {
result.add(new JavaElementChildrenProperty(this, "COMPILATION UNITS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, packageFragment.getCompilationUnits());
}
});
result.add(new JavaElementChildrenProperty(this, "CLASS FILES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, packageFragment.getAllClassFiles());
}
});
result.add(new JavaElementChildrenProperty(this, "NON JAVA RESOURCES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createResources(this, packageFragment.getNonJavaResources());
}
});
}
private void addTypeRootChildren(ArrayList<JEAttribute> result, final ITypeRoot typeRoot) {
result.add(JavaElement.compute(this, "FIND PRIMARY TYPE", () -> typeRoot.findPrimaryType()));
}
private void addClassFileChildren(ArrayList<JEAttribute> result, final IOrdinaryClassFile classFile) {
result.add(JavaElement.compute(this, "TYPE", () -> classFile.getType()));
}
private void addModularClassFileChildren(ArrayList<JEAttribute> result, final IModularClassFile classFile) {
result.add(JavaElement.compute(this, "MODULE", () -> classFile.getModule()));
}
private void addCompilationUnitChildren(ArrayList<JEAttribute> result, final ICompilationUnit compilationUnit) {
//TODO: WorkingCopyOwner
result.add(new JavaElement(this, "PRIMARY", compilationUnit.getPrimary()));
result.add(new JavaElementChildrenProperty(this, "TYPES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, compilationUnit.getTypes());
}
});
result.add(new JavaElementChildrenProperty(this, "ALL TYPES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, compilationUnit.getAllTypes());
}
});
result.add(new JavaElement(this, "IMPORT CONTAINER", compilationUnit.getImportContainer()));
result.add(new JavaElementChildrenProperty(this, "IMPORTS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, compilationUnit.getImports());
}
});
result.add(new JavaElementChildrenProperty(this, "PACKAGE DECLARATIONS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, compilationUnit.getPackageDeclarations());
}
});
}
private void addMemberChildren(ArrayList<JEAttribute> result, final IMember member) {
result.add(new JavaElement(this, "CLASS FILE", member.getClassFile()));
result.add(new JavaElement(this, "COMPILATION UNIT", member.getCompilationUnit()));
result.add(new JavaElement(this, "TYPE ROOT", member.getTypeRoot()));
result.add(new JavaElement(this, "DECLARING TYPE", member.getDeclaringType()));
result.add(new JavaElementChildrenProperty(this, "CATEGORIES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createStrings(this, member.getCategories());
}
});
}
private void addAnnotationChildren(ArrayList<JEAttribute> result, final IAnnotation annotation) {
result.add(new JavaElementChildrenProperty(this, "MEMBER VALUE PAIRS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
IMemberValuePair[] memberValuePairs= annotation.getMemberValuePairs();
return createMemberValuePairs(this, memberValuePairs);
}
});
}
private void addAnnotatableChildren(ArrayList<JEAttribute> result, final IAnnotatable annotatable) {
result.add(new JavaElementChildrenProperty(this, "ANNOTATIONS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
IAnnotation[] annotations= annotatable.getAnnotations();
return createJavaElements(this, annotations);
}
});
}
private void addTypeChildren(ArrayList<JEAttribute> result, final IType type) {
result.add(new JavaElementProperty(this, "IS RESOLVED", type.isResolved()));
result.add(new JavaElementProperty(this, "KEY", type.getKey()));
result.add(new JavaElement(this, "PACKAGE FRAGMENT", type.getPackageFragment()));
result.add(new JavaElementChildrenProperty(this, "TYPE PARAMETERS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, type.getTypeParameters());
}
});
result.add(new JavaElementChildrenProperty(this, "TYPE PARAMETER SIGNATURES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createStrings(this, type.getTypeParameterSignatures());
}
});
result.add(new JavaElementProperty(this, "SUPERCLASS NAME") {
@Override
protected Object computeValue() throws Exception {
return type.getSuperclassName();
}
});
result.add(new JavaElementProperty(this, "SUPERCLASS TYPE SIGNATURE") {
@Override
protected Object computeValue() throws Exception {
return type.getSuperclassTypeSignature();
}
});
result.add(new JavaElementChildrenProperty(this, "SUPER INTERFACE NAMES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createStrings(this, type.getSuperInterfaceNames());
}
});
result.add(new JavaElementChildrenProperty(this, "SUPER INTERFACE TYPE SIGNATURES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createStrings(this, type.getSuperInterfaceTypeSignatures());
}
});
result.add(new JavaElementChildrenProperty(this, "FIELDS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, type.getFields());
}
});
result.add(new JavaElementChildrenProperty(this, "INITIALIZERS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, type.getInitializers());
}
});
result.add(new JavaElementChildrenProperty(this, "METHODS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, type.getMethods());
}
});
result.add(new JavaElementChildrenProperty(this, "TYPES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, type.getTypes());
}
});
}
private void addMethodChildren(ArrayList<JEAttribute> result, final IMethod method) {
result.add(new JavaElementChildrenProperty(this, "EXCEPTION TYPES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createStrings(this, method.getExceptionTypes());
}
});
result.add(new JavaElementChildrenProperty(this, "PARAMETERS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, method.getParameters());
}
});
result.add(new JavaElementChildrenProperty(this, "PARAMETER NAMES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createStrings(this, method.getParameterNames());
}
});
result.add(new JavaElementChildrenProperty(this, "PARAMETER TYPES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createStrings(this, method.getParameterTypes());
}
});
result.add(new JavaElementChildrenProperty(this, "TYPE PARAMETERS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createJavaElements(this, method.getTypeParameters());
}
});
result.add(new JavaElementChildrenProperty(this, "TYPE PARAMETER SIGNATURES") {
@Override @Deprecated
protected JEAttribute[] computeChildren() throws JavaModelException {
return createStrings(this, method.getTypeParameterSignatures());
}
});
try {
result.add(new JEMemberValuePair(this, "DEFAULT_VALUE", method.getDefaultValue()));
} catch (JavaModelException e) {
result.add(new Error(this, "DEFAULT_VALUE", e));
}
}
private void addTypeParameterChildren(ArrayList<JEAttribute> result, final ITypeParameter typeParameter) {
result.add(new JavaElement(this, "TYPE ROOT", typeParameter.getTypeRoot()));
result.add(new JavaElement(this, "DECLARING MEMBER", typeParameter.getDeclaringMember()));
result.add(new JavaElementChildrenProperty(this, "BOUNDS") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createStrings(this, typeParameter.getBounds());
}
});
result.add(new JavaElementChildrenProperty(this, "BOUNDS SIGNATURES") {
@Override
protected JEAttribute[] computeChildren() throws JavaModelException {
return createStrings(this, typeParameter.getBoundsSignatures());
}
});
}
private void addLocalVariableChildren(ArrayList<JEAttribute> result, final ILocalVariable localVariable) {
result.add(new JavaElement(this, "TYPE ROOT", localVariable.getTypeRoot()));
result.add(new JavaElement(this, "DECLARING MEMBER", localVariable.getDeclaringMember()));
}
static JavaElement[] createJavaElements(JEAttribute parent, Object[] javaElements) {
JavaElement[] jeChildren= new JavaElement[javaElements.length];
for (int i= 0; i < javaElements.length; i++) {
jeChildren[i]= new JavaElement(parent, (IJavaElement) javaElements[i]);
}
return jeChildren;
}
static JavaElement[] createJavaElements(JEAttribute parent, IJavaElement[] javaElements) {
JavaElement[] jeChildren= new JavaElement[javaElements.length];
for (int i= 0; i < javaElements.length; i++) {
jeChildren[i]= new JavaElement(parent, javaElements[i]);
}
return jeChildren;
}
static JEAttribute[] createResources(JEAttribute parent, Object[] resources) {
JEAttribute[] resourceChildren= new JEAttribute[resources.length];
for (int i= 0; i < resources.length; i++) {
Object resource= resources[i];
if (resource instanceof IResource)
resourceChildren[i]= new JEResource(parent, null, (IResource) resource);
else if (resource instanceof IJarEntryResource)
resourceChildren[i]= new JEJarEntryResource(parent, null, (IJarEntryResource) resource);
else
resourceChildren[i]= new JavaElementProperty(parent, null, resource);
}
return resourceChildren;
}
static JEAttribute[] createMemberValuePairs(JEAttribute parent, IMemberValuePair[] mvPairs) {
JEAttribute[] mvPairChildren= new JEAttribute[mvPairs.length];
for (int i= 0; i < mvPairs.length; i++) {
IMemberValuePair mvPair= mvPairs[i];
mvPairChildren[i]= new JEMemberValuePair(parent, mvPair);
}
return mvPairChildren;
}
static JEAttribute[] createCPEntries(JEAttribute parent, IClasspathEntry[] entries) {
JEAttribute[] entryChildren= new JEAttribute[entries.length];
for (int i= 0; i < entries.length; i++) {
IClasspathEntry entry= entries[i];
entryChildren[i]= new JEClasspathEntry(parent, null, entry);
}
return entryChildren;
}
static JEAttribute[] createOptions(JEAttribute parent, Map<String, String> options) {
ArrayList<Entry<String, String>> entries= new ArrayList<>(options.entrySet());
Collections.sort(entries, Comparator.comparing(Entry<String, String>::getKey));
JEAttribute[] children= new JEAttribute[entries.size()];
for (int i= 0; i < entries.size(); i++) {
Entry<String, String> entry= entries.get(i);
children[i]= new JavaElementProperty(parent, entry.getKey(), entry.getValue());
}
return children;
}
static JEAttribute[] createStrings(JEAttribute parent, String[] strings) {
JEAttribute[] children= new JEAttribute[strings.length];
for (int i= 0; i < strings.length; i++) {
children[i]= new JavaElementProperty(parent, null, strings[i]);
}
return children;
}
public static JEAttribute compute(JEAttribute parent, String name, Callable<IJavaElement> computer) {
try {
IJavaElement javaElement= computer.call();
return create(parent, name, javaElement);
} catch (Exception e) {
return new Error(parent, name, e);
}
}
public static JEAttribute create(JEAttribute parent, String name, IJavaElement javaElement) {
if (javaElement == null) {
return new Null(parent, name);
} else {
return new JavaElement(parent, name, javaElement);
}
}
}