Commit 1f2ca45a authored by Daniel Bluhm's avatar Daniel Bluhm

Add required import parsing from type

Signed-off-by: Daniel Bluhm's avatarDaniel Bluhm <bluhmdj@ornl.gov>
parent 02d4b145
package org.eclipse.ice.dev.annotations.processors;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.lang.model.element.Modifier;
......@@ -32,6 +38,25 @@ import lombok.Singular;
@JsonDeserialize(builder = Field.FieldBuilder.class)
public class Field {
/**
* Import matcher regex.
*
* Consider the following string:
*
* <pre>
* {@code java.util.Map$Entry<java.lang.String, java.lang.Object>}
* </pre>
*
* {@code $Entry} will match separately with this regex, allowing us to test
* for strings beginning with {@code $} and dropping it from the imports. We
* do this because inner classes are accessed through their parent class so
* it is the parent class that must be imported. This will also drop values
* to be interpolated by Velocity (as in the case of the
* {@link DefaultFields}' JavascriptValidator) which happens to use the same
* {@code $} character for variable interpolation.
*/
private static final Pattern IMPORT_RE = Pattern.compile("(\\$?[a-zA-Z0-9.]+)");
/**
* Name of the field.
*/
......@@ -143,19 +168,6 @@ public class Field {
return this.varName != null;
}
/**
* Get a class by name or return null if not found
* @param cls
* @return found class or null
*/
private static Class<?> getClassOrNull(String cls) {
try {
return ClassUtils.getClass(cls);
} catch (ClassNotFoundException e) {
return null;
}
}
/**
* Return this Fields name ready for use in a method name.
* @return capitalized name
......@@ -193,6 +205,57 @@ public class Field {
return this.modifiers.contains("final");
}
/**
* Return if this field requires an import.
* @return true if field type requires an import.
*/
@JsonIgnore
public boolean requiresImports() {
return type.contains(".") && !ClassUtils.getPackageName(type).equals("java.lang");
}
/**
* Return set of strings representing the required imports of this field.
* @return set of strings to import
*/
@JsonIgnore
public Set<String> getImports() {
Set<String> imports = new HashSet<>();
Matcher matcher = IMPORT_RE.matcher(type);
while (matcher.find()) {
String match = matcher.group();
// Inner classes and Velocity interpolated variables not included
// in imports. No need to import java.lang package (i.e. String is
// already available without import).
if (!match.startsWith("$") && !match.startsWith("java.lang")) {
imports.add(match);
}
}
return imports;
}
/**
* Return the short name of this field's type.
* @return the short name of this field's type.
*/
@JsonIgnore
public String getShortType() {
return ClassUtils.getShortCanonicalName(type);
}
/**
* Get a class by name or return null if not found
* @param cls
* @return found class or null
*/
private static Class<?> getClassOrNull(String cls) {
try {
return ClassUtils.getClass(cls);
} catch (ClassNotFoundException e) {
return null;
}
}
/**
* Instruct Jackson how to deserialize fields.
*/
......
......@@ -5,6 +5,8 @@ package org.eclipse.ice.tests.dev.annotations.processors;
import static org.junit.jupiter.api.Assertions.*;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.eclipse.ice.dev.annotations.processors.Field;
......@@ -86,4 +88,107 @@ class FieldTest {
assertEquals("test", f.getVarName());
assertFalse(f.isVarNameDifferent());
}
/**
* Test getShortType.
*/
@Test
void testGetShortType() {
Field f = Field.builder()
.name("test")
.type(String.class)
.build();
assertEquals("String", f.getShortType());
f = Field.builder()
.name("test")
.type(boolean.class)
.build();
assertEquals("boolean", f.getShortType());
f = Field.builder()
.name("test")
.type(UUID.class)
.build();
assertEquals("UUID", f.getShortType());
f = Field.builder()
.name("test")
.type(Map.Entry.class)
.build();
assertEquals("Map.Entry", f.getShortType());
f = Field.builder()
.name("test")
.type("java.util.Map$Entry<String, Object>")
.build();
assertEquals("Map.Entry<String,Object>", f.getShortType());
}
/**
* Test requiresImport.
*/
@Test
void testRequiresImport() {
Field f = Field.builder()
.name("test")
.type(String.class)
.build();
assertFalse(f.requiresImports());
f = Field.builder()
.name("test")
.type(boolean.class)
.build();
assertFalse(f.requiresImports());
f = Field.builder()
.name("test")
.type(UUID.class)
.build();
assertTrue(f.requiresImports());
}
/**
* Test getImports.
*/
@Test
void testGetImports() {
Field f = Field.builder()
.name("test")
.type(UUID.class)
.build();
assertTrue(f.getImports().contains("java.util.UUID"));
f = Field.builder()
.name("test")
.type(String.class)
.build();
Set<String> imports = f.getImports();
assertFalse(imports.contains("java.lang.String"));
assertTrue(imports.isEmpty());
f = Field.builder()
.name("test")
.type(Map.Entry.class)
.build();
assertTrue(f.getImports().contains("java.util.Map"));
f = Field.builder()
.name("test")
.type("java.util.Map$Entry<java.lang.String, java.lang.Object>")
.build();
imports = f.getImports();
assertTrue(imports.contains("java.util.Map"));
assertFalse(imports.contains("java.lang.String"));
assertFalse(imports.contains("java.lang.Object"));
f = Field.builder()
.name("test")
.type("java.util.List<java.lang.String>")
.build();
imports = f.getImports();
assertTrue(f.getImports().contains("java.util.List"));
assertFalse(f.getImports().contains("java.lang.String"));
f = Field.builder()
.name("test")
.type("java.util.Map<java.lang.String, java.util.List<java.util.Map$Entry<$interface, java.lang.String>>>")
.build();
imports = f.getImports();
assertTrue(f.getImports().contains("java.util.Map"));
assertTrue(f.getImports().contains("java.util.List"));
assertFalse(f.getImports().contains("java.lang.String"));
assertFalse(f.getImports().contains("$Entry"));
assertFalse(f.getImports().contains("$interface"));
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment