Avoid classloading in TypeUtil.isCollection
Use type information from project classpath index instead.
This commit is contained in:
@@ -70,7 +70,7 @@ public class CommonLanguageTools {
|
||||
|
||||
public static Collection<StsValueHint> getValueHints(FuzzyMap<PropertyInfo> index, TypeUtil typeUtil, String query, String propertyName, EnumCaseMode caseMode) {
|
||||
Type type = getValueType(index, typeUtil, propertyName);
|
||||
if (TypeUtil.isSequencable(type)) {
|
||||
if (typeUtil.isSequencable(type)) {
|
||||
//It is useful to provide content assist for the values in the list when entering a list
|
||||
type = TypeUtil.getDomainType(type);
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ public class PropertyInfo {
|
||||
Type type = TypeParser.parse(this.type);
|
||||
if (typeUtil.isMap(type)) {
|
||||
return HintProviders.forMap(keyHints(typeUtil), valueHints(typeUtil), TypeUtil.getDomainType(type));
|
||||
} else if (TypeUtil.isSequencable(type)) {
|
||||
} else if (typeUtil.isSequencable(type)) {
|
||||
return HintProviders.forAllValueContexts(valueHints(typeUtil));
|
||||
} else {
|
||||
return HintProviders.forHere(valueHints(typeUtil));
|
||||
|
||||
@@ -99,6 +99,9 @@ public class TypeUtil {
|
||||
|
||||
private static final Object OBJECT_TYPE_NAME = Object.class.getName();
|
||||
private static final String STRING_TYPE_NAME = String.class.getName();
|
||||
private static final String MAP_TYPE_NAME = Map.class.getName();
|
||||
private static final String SET_TYPE_NAME = Set.class.getName();
|
||||
private static final String LIST_TYPE_NAME = List.class.getName();
|
||||
private static final String INET_ADDRESS_TYPE_NAME = InetAddress.class.getName();
|
||||
private static final String DURATION_TYPE_NAME = Duration.class.getName();
|
||||
private static final String CLASS_TYPE_NAME = Class.class.getName();
|
||||
@@ -443,7 +446,7 @@ public class TypeUtil {
|
||||
* use the notation <name>[<index>]=<value> in property file
|
||||
* for properties of this type.
|
||||
*/
|
||||
public static boolean isBracketable(Type type) {
|
||||
public boolean isBracketable(Type type) {
|
||||
//Note array types where once not considered 'Bracketable'
|
||||
//see: STS-4031
|
||||
|
||||
@@ -452,32 +455,13 @@ public class TypeUtil {
|
||||
//This is actually more logical too.
|
||||
//So '[' notation in props file can be used for either list or arrays (at least in recent versions of boot).
|
||||
//Note also 'Set' are now considered bracketable. See: https://www.pivotaltracker.com/story/show/154644992
|
||||
return isArray(type) || isCollection(List.class, type) || isCollection(Set.class, type);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static boolean isCollection( Class<? extends Collection> klass, Type type) {
|
||||
//Note: to be really correct we should use JDT infrastructure to resolve
|
||||
//type in project classpath instead of using Java reflection.
|
||||
//However, use reflection here is okay assuming types we care about
|
||||
//are part of JRE standard libraries. Using eclipse 'type hirearchy' would
|
||||
//also potentialy be very slow.
|
||||
if (type!=null) {
|
||||
String erasure = type.getErasure();
|
||||
try {
|
||||
Class<?> erasureClass = Class.forName(erasure);
|
||||
return klass.isAssignableFrom(erasureClass);
|
||||
} catch (Exception e) {
|
||||
//type not resolveable assume its not 'array like'
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return isArray(type) || isCollection(LIST_TYPE_NAME, type) || isCollection(SET_TYPE_NAME, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if type can be treated / represented as a sequence node in .yml file
|
||||
*/
|
||||
public static boolean isSequencable(Type type) {
|
||||
public boolean isSequencable(Type type) {
|
||||
return isBracketable(type);
|
||||
}
|
||||
|
||||
@@ -486,21 +470,15 @@ public class TypeUtil {
|
||||
}
|
||||
|
||||
public boolean isMap(Type type) {
|
||||
//Note: to be really correct we should use JDT infrastructure to resolve
|
||||
//type in project classpath instead of using Java reflection.
|
||||
//However, use reflection here is okay assuming types we care about
|
||||
//are part of JRE standard libraries. Using eclipse 'type hirearchy' would
|
||||
//also potentialy be very slow.
|
||||
if (type!=null) {
|
||||
String erasure = type.getErasure();
|
||||
if ("java.util.Map".equals(erasure)) {
|
||||
if (MAP_TYPE_NAME.equals(erasure)) {
|
||||
//quick / easy case. No looking for types and hierarchies required.
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
IType mapType = findType("java.util.Map");
|
||||
IType erasureType = findType(erasure);
|
||||
return isAssignableFrom(mapType, erasureType);
|
||||
return isAssignableFrom(MAP_TYPE_NAME, erasureType);
|
||||
} catch (Exception e) {
|
||||
//type not resolveable
|
||||
}
|
||||
@@ -508,9 +486,27 @@ public class TypeUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isAssignableFrom(IType mapType, IType erasureType) {
|
||||
private boolean isCollection(String collectionTypeName, Type type) {
|
||||
if (type!=null) {
|
||||
String erasure = type.getErasure();
|
||||
if (collectionTypeName.equals(erasure)) {
|
||||
//quick / easy case. No looking for types and hierarchies required.
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
IType erasureType = findType(erasure);
|
||||
return isAssignableFrom(collectionTypeName, erasureType);
|
||||
} catch (Exception e) {
|
||||
//type not resolveable
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private boolean isAssignableFrom(String superTypeName, IType erasureType) {
|
||||
Set<String> seen = new HashSet<>();
|
||||
return searchSuperTypes(seen, erasureType, mapType.getFullyQualifiedName());
|
||||
return searchSuperTypes(seen, erasureType, superTypeName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ public class PropertiesCompletionProposalsCalculator {
|
||||
if (type!=null) {
|
||||
if (typeUtil.isAssignableType(type)) {
|
||||
postfix = "=";
|
||||
} else if (TypeUtil.isBracketable(type)) {
|
||||
} else if (typeUtil.isBracketable(type)) {
|
||||
postfix = "[";
|
||||
} else if (typeUtil.isDotable(type)) {
|
||||
postfix = ".";
|
||||
|
||||
@@ -77,22 +77,23 @@ class PropertiesHoverCalculator {
|
||||
if (valueRegion.getStart() <= propertyFinder.offset && propertyFinder.offset < valueRegion.getEnd()) {
|
||||
String valueString = valueRegion.toString();
|
||||
String propertyName = value.getParent().getKey().decode();
|
||||
Type type = getValueType(propertyFinder.index, propertyFinder.typeUtil, propertyName);
|
||||
if (TypeUtil.isSequencable(type)) {
|
||||
TypeUtil typeUtil = propertyFinder.typeUtil;
|
||||
Type type = getValueType(propertyFinder.index, typeUtil, propertyName);
|
||||
if (typeUtil.isSequencable(type)) {
|
||||
//It is useful to provide content assist for the values in the list when entering a list
|
||||
type = TypeUtil.getDomainType(type);
|
||||
}
|
||||
if (TypeUtil.isClass(type)) {
|
||||
//Special case. We want to provide hoverinfos more liberally than what's suggested for completions (i.e. even class names
|
||||
//that are not suggested by the hints because they do not meet subtyping constraints should be hoverable and linkable!
|
||||
StsValueHint hint = StsValueHint.className(valueString, propertyFinder.typeUtil);
|
||||
StsValueHint hint = StsValueHint.className(valueString, typeUtil);
|
||||
if (hint!=null) {
|
||||
return Tuples.of(createRenderable(hint), valueRegion.asRegion());
|
||||
}
|
||||
}
|
||||
//Hack: pretend to invoke content-assist at the end of the value text. This should provide hints applicable to that value
|
||||
// then show hoverinfo based on that. That way we can avoid duplication a lot of similar logic to compute hoverinfos and hyperlinks.
|
||||
Collection<StsValueHint> hints = getValueHints(propertyFinder.index, propertyFinder.typeUtil, valueString, propertyName, EnumCaseMode.ALIASED);
|
||||
Collection<StsValueHint> hints = getValueHints(propertyFinder.index, typeUtil, valueString, propertyName, EnumCaseMode.ALIASED);
|
||||
if (hints!=null) {
|
||||
Optional<StsValueHint> hint = hints.stream().filter(h -> valueString.equals(h.getValue())).findFirst();
|
||||
if (hint.isPresent()) {
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
|
||||
package org.springframework.ide.vscode.boot.properties.reconcile;
|
||||
|
||||
import static org.springframework.ide.vscode.boot.metadata.types.TypeUtil.isBracketable;
|
||||
import static org.springframework.ide.vscode.boot.properties.reconcile.SpringPropertyProblem.problem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ide.vscode.boot.metadata.types.Type;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypedProperty;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.BeanPropertyNameMode;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.EnumCaseMode;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypedProperty;
|
||||
import org.springframework.ide.vscode.boot.properties.completions.SpringPropertiesCompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
@@ -87,7 +87,7 @@ public class PropertyNavigator {
|
||||
offset, region.getEnd()-offset));
|
||||
}
|
||||
} else if (navOp=='[') {
|
||||
if (isBracketable(type)) {
|
||||
if (typeUtil.isBracketable(type)) {
|
||||
return bracketNavigate(offset, type);
|
||||
} else {
|
||||
problemCollector.accept(problem(ApplicationPropertiesProblemType.PROP_INVALID_INDEXED_NAVIGATION,
|
||||
|
||||
@@ -119,7 +119,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
if (typeUtil.isMap(type)) {
|
||||
//ready to enter nested map key on next line
|
||||
return "\n"+YamlIndentUtil.INDENT_STR;
|
||||
} if (TypeUtil.isSequencable(type)) {
|
||||
} if (typeUtil.isSequencable(type)) {
|
||||
//ready to enter sequence element on next line
|
||||
return "\n- ";
|
||||
} else if (typeUtil.isAtomic(type)) {
|
||||
@@ -328,7 +328,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
@Override
|
||||
public YamlAssistContext traverse(YamlPathSegment s) {
|
||||
if (s.getType()==YamlPathSegmentType.VAL_AT_KEY) {
|
||||
if (TypeUtil.isSequencable(type) || typeUtil.isMap(type)) {
|
||||
if (typeUtil.isSequencable(type) || typeUtil.isMap(type)) {
|
||||
return contextWith(s, TypeUtil.getDomainType(type));
|
||||
}
|
||||
String key = s.toPropString();
|
||||
@@ -337,7 +337,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
return contextWith(s, TypedProperty.typeOf(subproperties.get(key)));
|
||||
}
|
||||
} else if (s.getType()==YamlPathSegmentType.VAL_AT_INDEX) {
|
||||
if (TypeUtil.isSequencable(type)) {
|
||||
if (typeUtil.isSequencable(type)) {
|
||||
return contextWith(s, TypeUtil.getDomainType(type));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ public class ApplicationYamlASTReconciler implements YamlASTReconciler {
|
||||
checkForDuplicateKeys(mapping);
|
||||
if (typeUtil.isAtomic(type)) {
|
||||
expectTypeFoundMapping(type, mapping);
|
||||
} else if (typeUtil.isMap(type) || TypeUtil.isSequencable(type)) {
|
||||
} else if (typeUtil.isMap(type) || typeUtil.isSequencable(type)) {
|
||||
Type keyType = typeUtil.getKeyType(type);
|
||||
Type valueType = TypeUtil.getDomainType(type);
|
||||
if (keyType!=null) {
|
||||
@@ -280,7 +280,7 @@ public class ApplicationYamlASTReconciler implements YamlASTReconciler {
|
||||
private void reconcile(YamlFileAST root, SequenceNode seq, Type type) {
|
||||
if (typeUtil.isAtomic(type)) {
|
||||
expectTypeFoundSequence(type, seq);
|
||||
} else if (TypeUtil.isSequencable(type)) {
|
||||
} else if (typeUtil.isSequencable(type)) {
|
||||
Type domainType = TypeUtil.getDomainType(type);
|
||||
if (domainType!=null) {
|
||||
for (Node element : seq.getValue()) {
|
||||
|
||||
Reference in New Issue
Block a user