I'm a developing a Java library that is going to be used internally in our company. It provides a wrapper around Aerospike. When a user calls the factory method, the library should read a file from its resources.
public static IAerospikeClient newTypedClient(IAerospikeClient client) {
LOG.info("Trying to load aerospike schema yml");
URL resource = AerospikeTypedClientFactory.class.getClassLoader().getResource("schema.yml");
if (resource == null) {
throw new IllegalArgumentException("File 'schema.yml' is not found");
}
byte[] bytes = Files.readAllBytes(Paths.get(resource.toURI()));
return new TypedAerospikeClient(client, new String(bytes));
}
Then I'm trying to add this library as a dependency and call newTypedClient
method, I get this error.
Caused by: java.nio.file.FileSystemNotFoundException
at com.sun.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:171)
at com.sun.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider.java:157)
at java.nio.file.Paths.get(Paths.java:143)
at com.example.AerospikeTypedClientFactory.newTypedClient(AerospikeTypedClientFactory.java:30)
Is there any way to overcome this error? I guess I could add the schema.yml
file to the resources
folder of the library's consumer. But I definitely don't want to go into this. Because the purpose is to get rid of configurations and put them within a single artefact.
For those who refer to How should I use getResource() in Java? question. I do understand that getResource
reads from the classpath. My question is how can I get this work? Perhaps, I can replace getResource
/getResourceAsStream
usage with something else. The idea is that schema.yml
has to be packed within the library .jar
archive.
Here is the problem step by step.
lib
module.lib
is packed to jar
and published to Artifactory.service
put a dependency on lib
.service
calls the newTypedClient
method from the lib
.FileSystemNotFoundException
raises.So, I need lib
to read schema.yml
from the jar it is packed to. Is it possible? Here is the diagram that describes the process.
For those who interested, I wrote a custom Gradle task that generates a class with the static String
field. This field value equals to the actual file content. The task runs before compileJava
one.
For the generation itself I use JavaPoet library.
Here is the example.
task generateSchemaClass {
def className = "Schema_"
def directoryPath = "src/main/java/com/example/generated"
def filePath = directoryPath + className + ".java"
doFirst {
TypeSpec typeSpec = TypeSpec.classBuilder("Schema_")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(
AnnotationSpec.builder(SuppressWarnings.class)
.addMember("value", '$S', "all")
.build()
)
.addField(
FieldSpec.builder(String.class, "CONTENT", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer('$S', file('src/main/resources/schema.yml').text)
.build()
)
.build()
JavaFile javaFile = JavaFile.builder("com.example.generated", typeSpec).build()
file(directoryPath).mkdirs()
def output = file(filePath)
output.createNewFile()
output.text = javaFile.toString()
}
}
compileJava.dependsOn(generateSchemaClass)