Jandex based Java Knowledge integration

This commit is contained in:
BoykoAlex
2016-11-08 10:19:58 -05:00
parent 6df038a93a
commit 010104ec8b
83 changed files with 3782 additions and 576 deletions

View File

@@ -18,5 +18,10 @@
<artifactId>commons-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jandex</artifactId>
<version>2.0.3.Final</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,30 @@
package org.springframework.ide.vscode.commons.jandex;
import static org.springframework.ide.vscode.commons.jandex.Wrappers.wrap;
import org.jboss.jandex.ArrayType;
import org.springframework.ide.vscode.commons.java.IArrayType;
import org.springframework.ide.vscode.commons.java.IJavaType;
final class ArrayTypeWrapper extends TypeWrapper<ArrayType> implements IArrayType {
ArrayTypeWrapper(ArrayType type) {
super(type);
}
@Override
public String name() {
return getType().name().toString();
}
@Override
public int dimensions() {
return getType().dimensions();
}
@Override
public IJavaType component() {
return wrap(getType().component());
}
}

View File

@@ -0,0 +1,17 @@
package org.springframework.ide.vscode.commons.jandex;
import org.jboss.jandex.ClassType;
import org.springframework.ide.vscode.commons.java.IClassType;
final class ClassTypeWrapper extends TypeWrapper<ClassType> implements IClassType {
ClassTypeWrapper(ClassType type) {
super(type);
}
@Override
public String name() {
return getType().name().toString();
}
}

View File

@@ -0,0 +1,124 @@
package org.springframework.ide.vscode.commons.jandex;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jboss.jandex.CompositeIndex;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexReader;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.Indexer;
import org.jboss.jandex.JarIndexer;
import org.springframework.ide.vscode.commons.java.IType;
import org.springframework.ide.vscode.commons.util.Log;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
public class JandexIndex {
@FunctionalInterface
public static interface IndexFileFinder {
File findIndexFile(File jarFile);
}
private Supplier<IndexView> index;
public JandexIndex(Stream<Path> classpathEntries) {
this(classpathEntries, jarFile -> null, Optional.empty());
}
public JandexIndex(Stream<Path> classpathEntries, IndexFileFinder indexFileFinder) {
this(classpathEntries, indexFileFinder, Optional.empty());
}
public JandexIndex(Stream<Path> classpathEntries, Optional<JandexIndex> baseIndex) {
this(classpathEntries, jarFile -> null, baseIndex);
}
public JandexIndex(Stream<Path> classpathEntries, IndexFileFinder indexFileFinder, Optional<JandexIndex> baseIndex) {
index = Suppliers.memoize(() -> {
if (baseIndex.isPresent()) {
return CompositeIndex.create(baseIndex.get().index.get(), buildIndex(classpathEntries, indexFileFinder));
} else {
return buildIndex(classpathEntries, indexFileFinder);
}
});
}
private static CompositeIndex buildIndex(Stream<Path> classpathEntries, IndexFileFinder indexFileFinder) {
return CompositeIndex.create(classpathEntries
.map(entry -> entry.toFile())
.map(file -> {
if (file.isFile() && file.getName().endsWith(".jar")) {
return indexJar(file, indexFileFinder);
} else if (file.isDirectory()) {
return indexFolder(file);
} else {
return Optional.<IndexView>empty();
}
})
.filter(o -> o.isPresent())
.map(o -> o.get())
.collect(Collectors.toList()));
}
private static Optional<IndexView> indexFolder(File folder) {
Indexer indexer = new Indexer();
for (Iterator<File> itr = com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(folder).iterator(); itr.hasNext();) {
File file = itr.next();
if (file.isFile() && file.getName().endsWith(".class")) {
try {
final InputStream stream = new FileInputStream(file);
try {
indexer.index(stream);
} finally {
try {
stream.close();
} catch (Exception ignore) {
}
}
} catch (Exception e) {
Log.log(e);
}
}
}
return Optional.of(indexer.complete());
}
private static Optional<IndexView> indexJar(File file, IndexFileFinder indexFileFinder) {
try {
File indexFile = indexFileFinder.findIndexFile(file);
if (indexFile != null) {
if (indexFile.createNewFile()) {
return Optional.of(JarIndexer
.createJarIndex(file, new Indexer(), indexFile,
false, false, true, System.out, System.err)
.getIndex());
} else {
return Optional.of(new IndexReader(new FileInputStream(indexFile)).read());
}
} else {
return Optional.of(JarIndexer
.createJarIndex(file, new Indexer(), file.canWrite(), file.getParentFile().canWrite(), true)
.getIndex());
}
} catch (IOException e) {
Log.log(e);
}
return Optional.empty();
}
public IType findType(String fqName) {
IndexView compositeIndex = index.get();
return Wrappers.wrap(compositeIndex, compositeIndex.getClassByName(DotName.createSimple(fqName)));
}
}

View File

@@ -0,0 +1,31 @@
package org.springframework.ide.vscode.commons.jandex;
import static org.springframework.ide.vscode.commons.jandex.Wrappers.wrap;
import java.util.stream.Stream;
import org.jboss.jandex.ParameterizedType;
import org.springframework.ide.vscode.commons.java.IJavaType;
import org.springframework.ide.vscode.commons.java.IParameterizedType;
final class ParameterizedTypeWrapper extends TypeWrapper<ParameterizedType> implements IParameterizedType {
ParameterizedTypeWrapper(ParameterizedType type) {
super(type);
}
@Override
public String name() {
return getType().name().toString();
}
@Override
public IJavaType owner() {
return wrap(getType().owner());
}
@Override
public Stream<IJavaType> arguments() {
return getType().arguments().stream().map(Wrappers::wrap);
}
}

View File

@@ -0,0 +1,17 @@
package org.springframework.ide.vscode.commons.jandex;
import org.jboss.jandex.TypeVariable;
import org.springframework.ide.vscode.commons.java.ITypeVariable;
final class TypeVariableWrapper extends TypeWrapper<TypeVariable> implements ITypeVariable {
TypeVariableWrapper(TypeVariable type) {
super(type);
}
@Override
public String name() {
return getType().name().toString();
}
}

View File

@@ -0,0 +1,34 @@
package org.springframework.ide.vscode.commons.jandex;
class TypeWrapper<T> {
private T type;
TypeWrapper(T type) {
this.type = type;
}
T getType() {
return type;
}
@Override
public int hashCode() {
return type.hashCode();
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object obj) {
if (obj instanceof TypeWrapper) {
return type.equals(((TypeWrapper<T>)obj).type);
}
return super.equals(obj);
}
@Override
public String toString() {
return type.toString();
}
}

View File

@@ -0,0 +1,17 @@
package org.springframework.ide.vscode.commons.jandex;
import org.jboss.jandex.UnresolvedTypeVariable;
import org.springframework.ide.vscode.commons.java.IUnresolvedTypeVariable;
final class UnresolvedTypeVariableWrapper extends TypeWrapper<UnresolvedTypeVariable> implements IUnresolvedTypeVariable {
UnresolvedTypeVariableWrapper(UnresolvedTypeVariable type) {
super(type);
}
@Override
public String name() {
return getType().name().toString();
}
}

View File

@@ -0,0 +1,17 @@
package org.springframework.ide.vscode.commons.jandex;
import org.jboss.jandex.WildcardType;
import org.springframework.ide.vscode.commons.java.IWildcardType;
final class WildcardTypeWrapper extends TypeWrapper<WildcardType> implements IWildcardType {
WildcardTypeWrapper(WildcardType type) {
super(type);
}
@Override
public String name() {
throw new UnsupportedOperationException("Not yet implemented");
}
}

View File

@@ -0,0 +1,350 @@
package org.springframework.ide.vscode.commons.jandex;
import static org.springframework.ide.vscode.commons.util.Assert.isNotNull;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.PrimitiveType;
import org.jboss.jandex.Type;
import org.springframework.ide.vscode.commons.java.IAnnotation;
import org.springframework.ide.vscode.commons.java.IField;
import org.springframework.ide.vscode.commons.java.IJavaType;
import org.springframework.ide.vscode.commons.java.IMemberValuePair;
import org.springframework.ide.vscode.commons.java.IMethod;
import org.springframework.ide.vscode.commons.java.IPrimitiveType;
import org.springframework.ide.vscode.commons.java.IType;
import org.springframework.ide.vscode.commons.java.IVoidType;
import org.springframework.ide.vscode.commons.util.HtmlSnippet;
public class Wrappers {
private static final int AccEnum = 0x4000;
public static IType wrap(IndexView index, ClassInfo info) {
if (info == null) {
return null;
}
return new IType() {
@Override
public int getFlags() {
return info.flags();
}
@Override
public IType getDeclaringType() {
DotName enclosingClass = info.enclosingClass();
return enclosingClass == null ? null : wrap(index, index.getClassByName(enclosingClass));
}
@Override
public String getElementName() {
return info.simpleName();
}
@Override
public HtmlSnippet getJavaDoc() {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public boolean exists() {
return true;
}
@Override
public Stream<IAnnotation> getAnnotations() {
// TODO: check correctness!
return info.annotations().get(info.name()).stream().map(Wrappers::wrap);
}
@Override
public boolean isClass() {
return true;
}
@Override
public boolean isEnum() {
return (info.flags() & AccEnum) != 0;
}
@Override
public boolean isInterface() {
return false;
}
@Override
public String getFullyQualifiedName() {
return info.name().toString();
}
@Override
public IField getField(String name) {
return wrap(index, info.field(name));
}
@Override
public Stream<IField> getFields() {
return info.fields().stream().map(f -> {
return wrap(index, f);
});
}
@Override
public IMethod getMethod(String name, Stream<IJavaType> parameters) {
List<Type> typeParameters = parameters.map(Wrappers::from).collect(Collectors.toList());
return wrap(index, info.method(name, typeParameters.toArray(new Type[typeParameters.size()])));
}
@Override
public Stream<IMethod> getMethods() {
return info.methods().stream().map(m -> {
return wrap(index, m);
});
}
@Override
public String toString() {
return info.toString();
}
};
}
public static IField wrap(IndexView index, FieldInfo field) {
if (field == null) {
return null;
}
return new IField() {
@Override
public int getFlags() {
return field.flags();
}
@Override
public IType getDeclaringType() {
return wrap(index, field.declaringClass());
}
@Override
public String getElementName() {
return field.name();
}
@Override
public HtmlSnippet getJavaDoc() {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public boolean exists() {
return true;
}
@Override
public Stream<IAnnotation> getAnnotations() {
return field.annotations().stream().map(a -> {
return wrap(a);
});
}
@Override
public boolean isEnumConstant() {
return (field.flags() & AccEnum) != 0;
}
@Override
public String toString() {
return field.toString();
}
};
}
public static IMethod wrap(IndexView index, MethodInfo method) {
isNotNull(index);
isNotNull(method);
return new IMethod() {
@Override
public int getFlags() {
return method.flags();
}
@Override
public IType getDeclaringType() {
return wrap(index, method.declaringClass());
}
@Override
public String getElementName() {
return method.name();
}
@Override
public HtmlSnippet getJavaDoc() {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public boolean exists() {
return true;
}
@Override
public Stream<IAnnotation> getAnnotations() {
return method.annotations().stream().map(Wrappers::wrap);
}
@Override
public IJavaType getReturnType() {
return wrap(method.returnType());
}
// @Override
// public String getSignature() {
// StringBuilder sb = new StringBuilder();
// sb.append('(');
// method.parameters().forEach(p -> sb.append(signature(p)));
// sb.append(')');
// sb.append(getReturnType());
// return sb.toString();
// }
@Override
public String toString() {
return method.toString();
}
@Override
public Stream<IJavaType> parameters() {
return method.parameters().stream().map(Wrappers::wrap);
}
};
}
public static IAnnotation wrap(AnnotationInstance annotation) {
isNotNull(annotation);
return new IAnnotation() {
@Override
public String getElementName() {
return annotation.name().toString();
}
@Override
public HtmlSnippet getJavaDoc() {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public boolean exists() {
return true;
}
@Override
public Stream<IMemberValuePair> getMemberValuePairs() {
return annotation.values().stream().map(av -> {
return wrap(av);
});
}
@Override
public String toString() {
return annotation.toString();
}
};
}
public static IMemberValuePair wrap(AnnotationValue annotationValue) {
if (annotationValue == null) {
return null;
}
return new IMemberValuePair() {
@Override
public String getMemberName() {
return annotationValue.name();
}
@Override
public Object getValue() {
return annotationValue.value();
}
@Override
public String toString() {
return annotationValue.toString();
}
};
}
public static Type createParameterTypeFromSignature(IndexView index, String signature) {
if (signature == null) {
return null;
}
throw new UnsupportedOperationException("Not yet implemented");
}
public static IPrimitiveType wrap(PrimitiveType type) {
switch (type.primitive()) {
case SHORT:
return IPrimitiveType.SHORT;
case LONG:
return IPrimitiveType.LONG;
case BYTE:
return IPrimitiveType.BYTE;
case DOUBLE:
return IPrimitiveType.DOUBLE;
case BOOLEAN:
return IPrimitiveType.BOOLEAN;
case CHAR:
return IPrimitiveType.CHAR;
case FLOAT:
return IPrimitiveType.FLOAT;
case INT:
return IPrimitiveType.INT;
}
throw new IllegalArgumentException("Invalid Java primitive type! " + type.toString());
}
@SuppressWarnings("unchecked")
private static Type from(IJavaType type) {
if (type instanceof TypeWrapper) {
return ((TypeWrapper<Type>)type).getType();
}
throw new IllegalArgumentException("Not a Jandex wrapped typed!");
}
public static IJavaType wrap(Type type) {
switch (type.kind()) {
case ARRAY:
return new ArrayTypeWrapper(type.asArrayType());
case CLASS:
return new ClassTypeWrapper(type.asClassType());
case PARAMETERIZED_TYPE:
return new ParameterizedTypeWrapper(type.asParameterizedType());
case PRIMITIVE:
return wrap(type.asPrimitiveType());
case TYPE_VARIABLE:
return new TypeVariableWrapper(type.asTypeVariable());
case UNRESOLVED_TYPE_VARIABLE:
return new UnresolvedTypeVariableWrapper(type.asUnresolvedTypeVariable());
case VOID:
return IVoidType.DEFAULT;
case WILDCARD_TYPE:
return new WildcardTypeWrapper(type.asWildcardType());
}
throw new IllegalArgumentException("Invalid Java Type " + type.toString());
}
}

View File

@@ -1,7 +1,9 @@
package org.springframework.ide.vscode.commons.java;
import java.util.stream.Stream;
public interface IAnnotatable extends IJavaElement {
IAnnotation[] getAnnotations();
Stream<IAnnotation> getAnnotations();
}

View File

@@ -1,5 +1,7 @@
package org.springframework.ide.vscode.commons.java;
import java.util.stream.Stream;
public interface IAnnotation extends IJavaElement {
/**
@@ -10,6 +12,6 @@ public interface IAnnotation extends IJavaElement {
*
* @return the member-value pairs of this annotation
*/
IMemberValuePair[] getMemberValuePairs();
Stream<IMemberValuePair> getMemberValuePairs();
}

View File

@@ -0,0 +1,9 @@
package org.springframework.ide.vscode.commons.java;
public interface IArrayType extends IJavaType {
int dimensions();
IJavaType component();
}

View File

@@ -0,0 +1,5 @@
package org.springframework.ide.vscode.commons.java;
public interface IClassType extends IJavaType {
}

View File

@@ -1,33 +1,33 @@
/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.java;
import java.nio.file.Path;
import java.util.Collection;
/**
* Classpath for a Java artifact
*
* @author Kris De Volder
* @author Alex Boyko
*
*/
public interface IClasspath {
/**
* Classpath entries paths
*
* @return collection of classpath entries in a form file/folder paths
* @throws Exception
*/
Collection<Path> getClasspathEntries() throws Exception;
}
/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.java;
import java.nio.file.Path;
import java.util.stream.Stream;
/**
* Classpath for a Java artifact
*
* @author Kris De Volder
* @author Alex Boyko
*
*/
public interface IClasspath {
/**
* Classpath entries paths
*
* @return collection of classpath entries in a form file/folder paths
* @throws Exception
*/
Stream<Path> getClasspathEntries() throws Exception;
}

View File

@@ -0,0 +1,7 @@
package org.springframework.ide.vscode.commons.java;
public interface IJavaType {
String name();
}

View File

@@ -1,5 +1,7 @@
package org.springframework.ide.vscode.commons.java;
import java.util.stream.Stream;
public interface IMethod extends IMember {
/**
@@ -20,28 +22,34 @@ public interface IMethod extends IMember {
* @return the type signature of the return value of this method, void for constructors
* @see Signature
*/
String getReturnType();
IJavaType getReturnType();
// /**
// * Returns the signature of this method. This includes the signatures for the
// * parameter types and return type, but does not include the method name,
// * exception types, or type parameters.
// * <p>
// * For example, a source method declared as <code>public void foo(String text, int length)</code>
// * would return <code>"(QString;I)V"</code>.
// * </p>
// * <p>
// * The type signatures embedded in the method signature may be either unresolved
// * (for source types) or resolved (for binary types), and either basic (for
// * basic types) or rich (for parameterized types). See {@link Signature} for
// * details.
// * </p>
// *
// * @return the signature of this method
// * @exception JavaModelException if this element does not exist or if an
// * exception occurs while accessing its corresponding resource.
// * @see Signature
// */
// String getSignature();
/**
* Returns the signature of this method. This includes the signatures for the
* parameter types and return type, but does not include the method name,
* exception types, or type parameters.
* <p>
* For example, a source method declared as <code>public void foo(String text, int length)</code>
* would return <code>"(QString;I)V"</code>.
* </p>
* <p>
* The type signatures embedded in the method signature may be either unresolved
* (for source types) or resolved (for binary types), and either basic (for
* basic types) or rich (for parameterized types). See {@link Signature} for
* details.
* </p>
*
* @return the signature of this method
* @exception JavaModelException if this element does not exist or if an
* exception occurs while accessing its corresponding resource.
* @see Signature
* Returns parameter types of this method
* @return
*/
String getSignature();
Stream<IJavaType> parameters();
}

View File

@@ -0,0 +1,11 @@
package org.springframework.ide.vscode.commons.java;
import java.util.stream.Stream;
public interface IParameterizedType extends IJavaType {
IJavaType owner();
Stream<IJavaType> arguments();
}

View File

@@ -0,0 +1,21 @@
package org.springframework.ide.vscode.commons.java;
public interface IPrimitiveType extends IJavaType {
static IPrimitiveType INT = () -> "I";
static IPrimitiveType BOOLEAN = () -> "Z";
static IPrimitiveType CHAR = () -> "C";
static IPrimitiveType FLOAT = () -> "F";
static IPrimitiveType BYTE = () -> "B";
static IPrimitiveType DOUBLE = () -> "D";
static IPrimitiveType LONG = () -> "J";
static IPrimitiveType SHORT = () -> "S";
}

View File

@@ -13,6 +13,8 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.java;
import java.util.stream.Stream;
/**
* Replaces eclipse JDT IType.
*/
@@ -56,7 +58,7 @@ public interface IType extends IMember {
*
* @return the fields declared by this type
*/
IField[] getFields();
Stream<IField> getFields();
/**
* Returns the method with the specified name and parameter types
@@ -76,7 +78,7 @@ public interface IType extends IMember {
* @param parameterTypeSignatures the given parameter types
* @return the method with the specified name and parameter types in this type
*/
IMethod getMethod(String name, String[] parameterTypeSignatures);
IMethod getMethod(String name, Stream<IJavaType> parameters);
/**
* Returns the methods and constructors declared by this type.
@@ -88,33 +90,33 @@ public interface IType extends IMember {
*
* @return the methods and constructors declared by this type
*/
IMethod[] getMethods();
Stream<IMethod> getMethods();
/**
* Resolves the given type name within the context of this type (depending on the type hierarchy
* and its imports).
* <p>
* Multiple answers might be found in case there are ambiguous matches.
* </p>
* <p>
* Each matching type name is decomposed as an array of two strings, the first denoting the package
* name (dot-separated) and the second being the type name. The package name is empty if it is the
* default package. The type name is the type qualified name using a '.' enclosing type separator.
* </p>
* <p>
* Returns <code>null</code> if unable to find any matching type.
* </p>
*<p>
* For example, resolution of <code>"Object"</code> would typically return
* <code>{{"java.lang", "Object"}}</code>. Another resolution that returns
* <code>{{"", "X.Inner"}}</code> represents the inner type Inner defined in type X in the
* default package.
* </p>
*
* @param typeName the given type name
* @return the resolved type names or <code>null</code> if unable to find any matching type
* @see #getTypeQualifiedName(char)
*/
String[][] resolveType(String typeName);
// /**
// * Resolves the given type name within the context of this type (depending on the type hierarchy
// * and its imports).
// * <p>
// * Multiple answers might be found in case there are ambiguous matches.
// * </p>
// * <p>
// * Each matching type name is decomposed as an array of two strings, the first denoting the package
// * name (dot-separated) and the second being the type name. The package name is empty if it is the
// * default package. The type name is the type qualified name using a '.' enclosing type separator.
// * </p>
// * <p>
// * Returns <code>null</code> if unable to find any matching type.
// * </p>
// *<p>
// * For example, resolution of <code>"Object"</code> would typically return
// * <code>{{"java.lang", "Object"}}</code>. Another resolution that returns
// * <code>{{"", "X.Inner"}}</code> represents the inner type Inner defined in type X in the
// * default package.
// * </p>
// *
// * @param typeName the given type name
// * @return the resolved type names or <code>null</code> if unable to find any matching type
// * @see #getTypeQualifiedName(char)
// */
// String[][] resolveType(String typeName);
}

View File

@@ -0,0 +1,5 @@
package org.springframework.ide.vscode.commons.java;
public interface ITypeVariable extends IJavaType {
}

View File

@@ -0,0 +1,5 @@
package org.springframework.ide.vscode.commons.java;
public interface IUnresolvedTypeVariable extends IJavaType {
}

View File

@@ -0,0 +1,14 @@
package org.springframework.ide.vscode.commons.java;
public interface IVoidType extends IJavaType {
static IVoidType DEFAULT = new IVoidType() {
@Override
public String name() {
return "V";
}
};
}

View File

@@ -0,0 +1,5 @@
package org.springframework.ide.vscode.commons.java;
public interface IWildcardType extends IJavaType {
}