18

I am trying to establish connection to a database. It's a simple project with using maven.

I have problems with sqljdbc_auth.dll

I have added mssql jdbc driver and added a dependency in pom.xml

<dependency>
    <groupId>com.microsoft</groupId>
    <artifactId>mssql-jdbc</artifactId>
    <version>4.0.0</version>
</dependency>

This is my try block

try {
    // Establish the connection. 
    SQLServerDataSource ds = new SQLServerDataSource();
    ds.setIntegratedSecurity(true);
    ds.setServerName("BUILDSRV");
    ds.setDatabaseName("master");
    ds.setIntegratedSecurity(true);
    con = ds.getConnection();       
}

and I get this error

    21.11.2012 18:07:04 com.microsoft.sqlserver.jdbc.AuthenticationJNI <clinit>
    WARNING: Failed to load the sqljdbc_auth.dll cause :- no sqljdbc_auth in       java.library.path
    com.microsoft.sqlserver.jdbc.SQLServerException:

I have my sqljdbc_auth.dll but I don't need to put it to my C:\windows\... I need to add it in my project from maven. How can I do this?

I tried to add it to the pom.xml but it doesn't work

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>1.1</version>
    <executions>
    <execution>
        <id>attach-artifacts</id>
        <goals>
            <goal>attach-artifact</goal>
        </goals>
        <configuration>
            <artifacts>
                <file>target</file>
                <type>dll</type>
            </artifacts>
        </configuration>
    </execution>
    </executions>
</plugin>

I got another error while building

Failed to execute goal org.codehaus.mojo:build-helper-maven-plugin:1.1:attach-artifact (attach-artifacts) on project mavenproject1dbconnect: Unable to parse configuration of mojo org.codehaus.mojo:build-helper-maven-plugin:1.1:attach-artifact for parameter file: Cannot configure instance of org.codehaus.mojo.buildhelper.Artifact from target -> [Help 1]
EricSchaefer
  • 25,272
  • 21
  • 67
  • 103
Kadymov Mukhammed
  • 193
  • 1
  • 1
  • 8
  • how do you intend to use your application, is it a webapp or a standalone deployment ? – mzzzzb Nov 22 '12 at 03:50
  • obviously you cannot add the dll in your jar, if it were possible, it would come in the jdbc jar itself in the first place, saving you all the trouble. we may have a solution which depends on how you intend to use your app – mzzzzb Nov 22 '12 at 03:52
  • not web. but a i can't say that it will be standalone, becouse i don't understand what it mean ) – Kadymov Mukhammed Nov 22 '12 at 08:59
  • i mean to say how you do you start your program. like `java MyClass` or `mvn exec:java ... ` or in some webcontainer. and how do you distribute your project, distribute as a jar ? – mzzzzb Nov 22 '12 at 09:27
  • now i start java myclass in netbeans ide. but in future i will have a lot of modules – Kadymov Mukhammed Nov 22 '12 at 10:16
  • The error message these others point refers to java.library.path , If it is a DLL it probably should be updated to the system OS environment"path"! Or run with local system command "path" append of the DLL along with the java command in the start .bat. in a server such as e.g. Tomcat you would assign that to path in something like it's setenv.sh or setenv.bat if there is not a special element for it in the server.xml. https://www.chilkatsoft.com/java-loadlibrary-windows.asp – Samuel Marchant Aug 17 '23 at 01:45
  • org.codehaus.mojo.buildhelper.Artifact. target. target should be a filename – Samuel Marchant Aug 17 '23 at 01:50

3 Answers3

0

i dont think you need to use the maven-helper-plugin here. The doc here says you either need to install the dll or specify its path in the system variable java.library.path.

Look at http://msdn.microsoft.com/en-us/library/ms378428.aspx#Connectingintegrated

UPDATE: make sure the dll is distributed along with your jar. If you are using a maven, Put the dll file in your src/main/resources folder. Then make sure the dll ends up outside the jar by excluding it from the package. Follow steps similar to ones outlined here. After this you should have your dll along with your built jar file in target directory

Then when you run the app pass system properties as commandline parameter java -Djava.library.path=..

If you prefer not to bother passing parameters via commandline -- you can extract current working directory using System.getProperty("user.dir")) and follow steps as stated here to set your java.library.path to current dir programatically in your main method

mzzzzb
  • 1,422
  • 19
  • 38
0

Based on information found in this answer, you could do it by injecting the dll into java.library.path at runtime.

I've had this running in production for a few years now with no problem on Java <= 8. Never really used with newer versions though. Quick tests worked with Java 11, not Java 15

Here's how I'm doing it:

  1. Have the dlls stored in your application path. For instance:
project_root
├─src (or any other source path structure)
│ └─...packages...
└─extlib
  └─SqlJdbc
    └─auth
      ├─x64
      │ └─sqljdbc_auth.dll
      └─x86
        └─sqljdbc_auth.dll
  1. Use the following static initialization code in the class that makes JDBC connection (java <= 11 version):
static {
    File file;
    if ("64".equals(System.getProperty("sun.arch.data.model")))
        file = new File("./extlib/SqlJdbc/auth/x64");
    else
        file = new File("./extlib/SqlJdbc/auth/x86");
    String dllPath;
    try {
        dllPath = file.getCanonicalPath();
        synchronized(Runtime.getRuntime()) {
            final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
            usrPathsField.setAccessible(true);
            Object o = usrPathsField.get(null);
            String[] paths = o == null ? new String[0] : (String[]) o;
            if (!Arrays.stream(paths).anyMatch(s -> dllPath.equals(s))) {
                String[] usr_paths = Arrays.copyOf(paths, paths.length + 1);
                usr_paths[paths.length] = file.getCanonicalPath();
                usrPathsField.set(null, usr_paths);
            }
        }
        DriverManager.registerDriver(new SQLServerDriver());
    } catch (Exception e) {
        e.printStackTrace();
        throw new ExceptionInInitializerError(e);
    }
}

According to this answer, you should be able to push it to at least Java <= 13 using MethodHandles.privateLookupIn instead of ClassLoader.class.getDeclaredField. For instance:

Lookup cl = MethodHandles.privateLookupIn(ClassLoader.class, MethodHandles.lookup());
VarHandle usrPathsField= cl.findStaticVarHandle(ClassLoader.class, "usr_paths", String[].class);
Object o = usrPathsField.get();
...
usrPathsField.set(usr_paths);

It's definitely broken with Java 15, as field usr_paths doesn't exist anymore in ClassLoader

At this point, you should be able to run your code from IDE

  1. Deploy the directory containing dlls (i.e. extlib) alongside your jar. For Maven, you can use the following in pom.xml:
<plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <version>3.0.2</version>
    <executions>
        <execution>
            <id>copy-resources</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-resources</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/extlib</outputDirectory>
                <resources>
                    <resource>
                        <directory>extlib</directory>
                        <filtering>false</filtering>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

From there, if you need your dlls packed inside your jar, you can do so using maven-resources-plugin, and unpack the required dll at runtime, and then force it onto the library path using a variation of above code.

julien.giband
  • 2,467
  • 1
  • 12
  • 19
0

It should be enough to put the dll directly on same level as your main jar. I suspect your problem has to do with x64 vs x86 versions of dll. Are you sure your versions align?

I'm using this dep:

<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>mssql-jdbc</artifactId>
    <version>9.1.1.jre8-preview</version>
</dependency>

And the dll:

mssql-jdbc_auth-9.1.1.x64-preview.dll

for my 64 bits project and it works fine

siggemannen
  • 3,884
  • 2
  • 6
  • 24