I'm trying to do a basic SQL query using JDBC and mysql-connector-java on an image with Graalvm (The cause of the problem).
Apparently everyone who tries to use GraalVM with JDBC/MySQL and Docker will have the same problem every time.
I'm having the following Exception
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.mysql.cj.Constants.<clinit>(Constants.java:49)
at com.mysql.cj.util.Util.<clinit>(Util.java:67)
at com.mysql.cj.conf.ConnectionUrl$Type.getImplementingInstance(ConnectionUrl.java:241)
at com.mysql.cj.conf.ConnectionUrl$Type.getConnectionUrlInstance(ConnectionUrl.java:211)
at com.mysql.cj.conf.ConnectionUrl.getConnectionUrlInstance(ConnectionUrl.java:280)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:195)
at java.sql.DriverManager.getConnection(DriverManager.java:681)
at java.sql.DriverManager.getConnection(DriverManager.java:229)
at com.me.test.Main.testJDBC(Main.java:73)
at com.me.test.Main.main(Main.java:94)
Caused by: java.lang.RuntimeException: Can't load resource bundle due to underlying exception java.util.MissingResourceException: Can't find bundle for base name com.mysql.cj.LocalizedErrorMessages, locale en_US
at com.mysql.cj.Messages.<clinit>(Messages.java:60)
... 10 more
Caused by: java.util.MissingResourceException: Can't find bundle for base name com.mysql.cj.LocalizedErrorMessages, locale en_US
at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:2045)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1683)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1586)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1549)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:858)
at com.mysql.cj.Messages.<clinit>(Messages.java:58)
... 10 more
My Dockerfile
FROM ghcr.io/graalvm/graalvm-ce:latest
RUN gu install native-image
WORKDIR /tmp/dist
ADD ./app.jar ./app.jar
COPY ./reflect-config.json ./reflect-config.json
RUN native-image -jar ./app.jar --verbose --no-fallback
RUN microdnf install zip
ADD bootstrap bootstrap
RUN chmod +x bootstrap
RUN chmod +x ./app
RUN zip -j function.zip bootstrap app
ENTRYPOINT ["./app"]
Dependencies in my pom file
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>21.5.0.0</version>
</dependency>
And finally my java code:
public void testJDBC() throws SQLException, IOException {
String url = "jdbc:mysql://foo.blabla.aws-region.rds.amazonaws.com:3306/database";
String user = "root";
String password = "password";
try(java.sql.Connection conn = java.sql.DriverManager.getConnection(url, user, password)){
doSomething(conn);
}
}
EDIT 1:
I followed Mark Rotteveel's recommendation, and added a "resource-config.json" file with the following:
{
"resources": {
"includes": [
{"pattern": "com.mysql.cj.LocalizedErrorMessages.properties"}
]
}
}
And in the "native-image.properties" file the following
Args = -H:EnableURLProtocols=http,https -H:ReflectionConfigurationFiles=/tmp/dist/reflect-config.json -H:ResourceConfigurationFiles=/tmp/dist/resource-config.json
Fixed the current error, but as expected we have a new one:
Exception in thread "main" java.lang.ClassCastException: com.mysql.cj.exceptions.CJException cannot be cast to com.mysql.cj.exceptions.WrongArgumentException
at com.mysql.cj.util.Util.getInstance(Util.java:169)
at com.mysql.cj.util.Util.getInstance(Util.java:174)
at com.mysql.cj.conf.ConnectionUrl$Type.getImplementingInstance(ConnectionUrl.java:241)
at com.mysql.cj.conf.ConnectionUrl$Type.getConnectionUrlInstance(ConnectionUrl.java:211)
at com.mysql.cj.conf.ConnectionUrl.getConnectionUrlInstance(ConnectionUrl.java:280)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:195)
at java.sql.DriverManager.getConnection(DriverManager.java:681)
at java.sql.DriverManager.getConnection(DriverManager.java:229)
at com.me.test.Main.testJDBC(Main.java:77)
at com.me.test.Main.main(Main.java:98)
EDIT 2:
I configured the following in the file "reflect-config.json"
[
{
"name": "com.mysql.cj.conf.url.SingleConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.FailoverDnsSrvConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.LoadBalanceDnsSrvConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.ReplicationDnsSrvConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.XDevApiDnsSrvConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.FailoverConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.LoadBalanceConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.ReplicationConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
}, {
"name": "com.mysql.cj.conf.url.XDevApiConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.log.Jdk14Logger",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.log.NullLogger",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.log.Slf4JLogger",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.log.StandardLogger",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.jdbc.Driver",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name":"oracle.jdbc.OracleDriver",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.jdbc.driver.T4CDriverExtension",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name" : "oracle.jdbc.driver.T2CDriverExtension",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.net.ano.Ano",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.net.ano.AuthenticationService",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.net.ano.DataIntegrityService",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.net.ano.EncryptionService",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.net.ano.SupervisorService",
"methods":[{"name":"<init>","parameterTypes":[] }]
}
]
But for some reason there is a connection error (Tested With AWS RDS, and host.docker.internal).
Exception in thread "main" java.sql.SQLNonTransientConnectionException: Cannot connect to MySQL server on foo.blabla.aws-region.rds.amazonaws.com:3,306.
Make sure that there is a MySQL server running on the machine/port you are trying to connect to and that the machine this software is running on is able to connect to this host/port (i.e. not firewalled). Also make sure that the server has not been started with the --skip-networking flag.
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:73)
at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:462)
at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:241)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:198)
at java.sql.DriverManager.getConnection(DriverManager.java:681)
at java.sql.DriverManager.getConnection(DriverManager.java:229)
at com.me.test.Main.testJDBC(Main.java:104)
at com.me.test.Main.main(Main.java:125)
Caused by: java.lang.ClassCastException: com.mysql.cj.exceptions.CJException cannot be cast to com.mysql.cj.exceptions.UnableToConnectException
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:825)
at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:448)
... 6 more
This error only occurs using "ghcr.io/graalvm/graalvm-ce:latest", if I use another VM like "amazoncorretto:18-alpine" everything works perfect.
Full Source Code: https://github.com/ederbaum/MySQLGraalVM
Any possible solution?