Skip to content

Commit

Permalink
Change Options.classPath to an array type
Browse files Browse the repository at this point in the history
The original classPath includes platform-specific path separator, compromising the cross-platform compatibility of the dumped options file. The changes also improve the usability of the Options class.
  • Loading branch information
zhangt2333 committed Oct 6, 2023
1 parent dd42085 commit a274938
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 24 deletions.
2 changes: 1 addition & 1 deletion java-benchmarks
13 changes: 5 additions & 8 deletions src/main/java/pascal/taie/AbstractWorldBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public abstract class AbstractWorldBuilder implements WorldBuilder {

protected static String getClassPath(Options options) {
if (options.isPrependJVM()) {
return options.getClassPath();
return String.join(File.pathSeparator, options.getClassPath());
} else { // when prependJVM is not set, we manually specify JRE jars
// check existence of JREs
File jreDir = new File(JREs);
Expand All @@ -86,8 +86,8 @@ protected static String getClassPath(Options options) {
try (Stream<Path> paths = Files.walk(Path.of(jrePath))) {
return Streams.concat(
paths.map(Path::toString).filter(p -> p.endsWith(".jar")),
Stream.ofNullable(options.getAppClassPath()),
Stream.ofNullable(options.getClassPath()))
options.getAppClassPath().stream(),
options.getClassPath().stream())
.collect(Collectors.joining(File.pathSeparator));
} catch (IOException e) {
throw new RuntimeException("Analysis on Java " +
Expand Down Expand Up @@ -124,11 +124,8 @@ protected static List<String> getInputClasses(Options options) {
}
});
// process --app-class-path
String appClassPath = options.getAppClassPath();
if (appClassPath != null) {
for (String path : appClassPath.split(File.pathSeparator)) {
classes.addAll(ClassNameExtractor.extract(path));
}
for (String path : options.getAppClassPath()) {
classes.addAll(ClassNameExtractor.extract(path));
}
return classes;
}
Expand Down
45 changes: 39 additions & 6 deletions src/main/java/pascal/taie/config/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,12 @@
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
* Option class for Tai-e.
Expand Down Expand Up @@ -95,21 +98,25 @@ public void printHelp() {

// ---------- program options ----------
@JsonProperty
@JsonSerialize(contentUsing = FilePathSerializer.class)
@Option(names = {"-cp", "--class-path"},
description = "Class path. Multiple paths are split by system path separator.")
private String classPath;
description = "Class path. Multiple paths are split by system path separator.",
converter = ClassPathConverter.class)
private List<String> classPath = List.of();

public String getClassPath() {
public List<String> getClassPath() {
return classPath;
}

@JsonProperty
@JsonSerialize(contentUsing = FilePathSerializer.class)
@Option(names = {"-acp", "--app-class-path"},
description = "Application class path." +
" Multiple paths are split by system path separator.")
private String appClassPath;
" Multiple paths are split by system path separator.",
converter = ClassPathConverter.class)
private List<String> appClassPath = List.of();

public String getAppClassPath() {
public List<String> getAppClassPath() {
return appClassPath;
}

Expand Down Expand Up @@ -449,6 +456,32 @@ public File deserialize(JsonParser p, DeserializationContext ctxt)
}
}

/**
* Converter for classpath with system path separator.
*/
private static class ClassPathConverter implements CommandLine.ITypeConverter<List<String>> {
@Override
public List<String> convert(String value) throws Exception {
return Arrays.stream(value.split(File.pathSeparator))
.map(String::trim)
.filter(Predicate.not(String::isEmpty))
.collect(Collectors.toList());
}
}

/**
* Serializer for file path. Ensures a path is serialized as a relative path
* from the working directory rather than an absolute path, thus
* preserving the portability of the dumped options file.
*/
private static class FilePathSerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen,
SerializerProvider serializers) throws IOException {
gen.writeString(toSerializedFilePath(value));
}
}

/**
* Convert a file to a relative path using the "/" (forward slash)
* from the working directory, thus preserving the portability of
Expand Down
11 changes: 2 additions & 9 deletions src/main/java/pascal/taie/frontend/cache/CachedWorldBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
Expand Down Expand Up @@ -162,14 +161,8 @@ private static int getWorldCacheHash(Options options) {
? options.getWorldBuilderClass().getName().hashCode() : 0);
// add the timestamp to the cache key calculation
List<String> paths = new ArrayList<>();
if (options.getClassPath() != null) {
paths.addAll(Arrays.asList(options.getClassPath()
.split(File.pathSeparator)));
}
if (options.getAppClassPath() != null) {
paths.addAll(Arrays.asList(options.getAppClassPath()
.split(File.pathSeparator)));
}
paths.addAll(options.getClassPath());
paths.addAll(options.getAppClassPath());
for (String path : paths) {
File file = new File(path);
if (file.exists()) {
Expand Down
14 changes: 14 additions & 0 deletions src/test/java/pascal/taie/config/OptionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import org.junit.jupiter.api.Test;

import java.io.File;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -90,4 +91,17 @@ void testKeepResult() {
options = Options.parse("-kr", "pta,def-use");
assertEquals(Set.of("pta", "def-use"), options.getKeepResult());
}

@Test
void testClasspath() {
Options options = Options.parse(
"-cp", ".\\a.jar",
"-cp", "./dir\\b",
"-cp", "./c" + File.pathSeparator + "d.jar",
"-cp", "e.jar" + File.pathSeparator
);
assertEquals(List.of(".\\a.jar", "./dir\\b", "./c", "d.jar", "e.jar"),
options.getClassPath());
}

}

0 comments on commit a274938

Please sign in to comment.