Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upJNA required on windows #112
Comments
|
I can't verify this with the following minimal example (Sample code, console output, Maven config). Can you please provide some more context? Can you provide the content of your import org.xbill.DNS.*;
public class Test {
public static void main(String[] args) throws TextParseException {
ResolverConfig.refresh();
Lookup lookup = new Lookup("example.com");
for (Record r : lookup.run()) {
System.out.println(r);
}
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>sample</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dnsjava</groupId>
<artifactId>dnsjava</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project> |
|
I'm using Version 3.0.2 of dnsjava os.name = Windows 10 JDK 1.8.241 This is running under a spring boot application. |
|
Seems to be fine on it's own but not under spring boot. On a side note, there doesn't seem to be a way of initializing the ResolverConfigProviders without initializing the ResolverConfig.refresh() being called first on it's existing list. We always pass in a resolver for all Lookup. So we don't want the default resolvers to be initialized. |
I'm not familiar with Spring Boot. Any idea what it's doing different?
This is/was intentional to avoid the need of calling refresh first, and I need to keep that behavior for backwards compatibility. I could add a property that skips the initialization. Would that help you?
|
I'm not entirely certain. If you provide that property to skip initialization that'd definitely help my problem. Thanks |
|
The property |
|
I've spent a bit more time looking at this. When running standalone, the NoClassDefFoundError is thrown for the class com.sun.jna.Pointer. This doesn't happen with SpringBoot. But the real question is why does it get thrown without spring boot? The WindowsResolverConfigProvider creates a new InnerWindowsResolverConfigProvider. That has no constructor and although the parent BaseResolverConfigProvider has some local members, nothing constructs a com.sun.jna.Pointer object. I wouldn't expect a NoClassDefFoundError thrown when constructing that Inner class. I think what would help is simply calling Class.forName("com.sun.jna.Pointer", false, this.getClass().getClassLoader()) in the constructor of WindowsResolverConfigProvider. If a ClassNotFoundException is thrown, then you know jna is not on the classpath.
I test Win32Exception as well as that is apart of the jna-platform (whereas Pointer is in the jna library) |
According to JLS §12.3, resolution of references in the Constant Pool can be lazy. Some classloaders like Spring Boot make use of this and would pass the NoClassDefFound check during construction, but fail later. See #112
|
I did some reading, and the different behavior is allowed according to JLS §12.3. Class loading consists of verification, preparation, resolution, initialization. Resolution can optionally be lazy, i.e. references to other classes like Pointer or Win32Exception can be resolved on demand; after initialization (= static and instance constructor(s)). Spring Boot seems to take adavantage of that option. I went for a slightly different approach: reference the two required classes in the static constructor. To pass initialization, they must be resolved. This is equivalent to Class.forName, the only difference is avoiding reflection (+ the log statement). |
JNA is currently required on windows. Although the code seems to imply it checks for JNA:
Just creating the WindowsResolverConfigProvider.InnerWindowsResolverConfigProvider will not cause a NoClassDefFoundError exception.
But will be thrown later on by the initialize() method causing the entire ResolverConfig to fail