当我使用 H2 数据库作为嵌入式时,Gluon 应用程序无法在 ios 上加载 FXML
Posted
技术标签:
【中文标题】当我使用 H2 数据库作为嵌入式时,Gluon 应用程序无法在 ios 上加载 FXML【英文标题】:Gluon Application can't load FXML on ios when I using H2 database as embedded 【发布时间】:2018-07-12 09:13:52 【问题描述】:我创建了使用 H2 数据库作为嵌入式模式的 Gluon 移动应用程序。它在 Window、Mac、android 上运行良好。但不幸的是它无法在 ios 模拟器上运行(无法加载 fxml)。
如果我注释代码以加载驱动程序,UI 将正确加载。
代码加载驱动程序
//load the driver class
try
Class.forName(DBCONFIG.DB_DRIVER).newInstance();
catch (ClassNotFoundException e)
System.out.println("class not found");
e.printStackTrace();
catch (IllegalAccessException e)
System.out.println("IllegalAccessException");
e.printStackTrace();
catch (InstantiationException e)
System.out.println("InstantiationException");
e.printStackTrace();
我还查看了this group 上的讨论,但没有运气。
我的代码:
private void createDB()
status.getItems().add("Creating a Database with H2");
//Get the private storage directory from each platform to save database files;
private_dir = GluonServices.getPrivateDirectory();
System.out.println("path="+private_dir.toString());
//load the driver class
try
Class.forName(DBCONFIG.DB_DRIVER).newInstance();
catch (ClassNotFoundException e)
System.out.println("class not found");
e.printStackTrace();
catch (IllegalAccessException e)
System.out.println("IllegalAccessException");
e.printStackTrace();
catch (InstantiationException e)
System.out.println("InstantiationException");
e.printStackTrace();
//Build Database connection string to the correct file that we create depending on each platform;
dbUrl = String.format(dbUrl,private_dir.toString(),DBCONFIG.DB_NAME);
System.out.println("dbUrl="+dbUrl);
List<Contact> list = new ArrayList<>();
try
//Connect to database from the giving db url: If file doesn't exist H2 will automatically create it.
System.out.println("getConnection=");
connection = DriverManager.getConnection(dbUrl);
status.getItems().add("Connection established: " + dbUrl);
//create the statement object
stmt = connection.createStatement();
stmt.setQueryTimeout(30);
String sql="DROP TABLE IF EXISTS contact;\n" +
"CREATE TABLE contact(\n" +
" Id INT NOT NULL AUTO_INCREMENT,\n" +
" Name VARCHAR(255) NOT NULL,\n" +
" Email VARCHAR(255) NOT NULL UNIQUE,\n" +
" PRIMARY KEY (ID)\n" +
");";
//execute query
stmt.executeUpdate(sql);
status.getItems().add("Starting Adding testing data and read it from database");
stmt.executeUpdate("INSERT INTO CONTACT(NAME,EMAIL) VALUES('Sovandara LENG','lengsovandara@gmail.com')");
stmt.executeUpdate("INSERT INTO CONTACT(NAME,EMAIL) VALUES('Chamroeun PANG','Chamroeun.p@gmail.com')");
stmt.executeUpdate("INSERT INTO CONTACT(NAME,EMAIL) VALUES('Sovanarith LENG','lengsovanarith@gmail.com')");
status.getItems().add("Retrieving records from table 'Contact'...");
rs = stmt.executeQuery("SELECT * FROM CONTACT");
while (rs.next())
int id = rs.getInt("Id");
String name = rs.getString("NAME");
String email = rs.getString("Email");
status.getItems().add(String.format("Record Added:id: %s, name: %s, email: %s",id,name,email));
list.add(new Contact(id,name, email));
status.getItems().add("End creating table and retrieving records");
if(list.size()>0)
status.getItems().add("Record has beed added");
System.out.println("Table Created");
status.getItems().add("Table Created");
catch (Exception e)
status.getItems().add("SQL error " + e.getMessage());
e.printStackTrace();
finally
try
if (rs != null)
rs.close();
catch (SQLException ex)
status.getItems().add("SQL error " + ex.getSQLState());
try
if (stmt != null)
stmt.close();
catch (SQLException ex)
status.getItems().add("SQL error " + ex.getSQLState());
Build.gradle
buildscript
repositories
jcenter()
dependencies
classpath 'org.javafxports:jfxmobile-plugin:1.3.12'
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.0'
apply plugin: 'org.javafxports.jfxmobile'
apply plugin: 'com.github.johnrengelman.shadow'
repositories
jcenter()
maven
url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
mainClassName = 'com.khmerdev.GluonApplication'
dependencies
compile 'com.gluonhq:charm:5.0.0'
compile files('libs/h2-1.4.196.jar')
// Add desktop dependencies to the task
shadowJar
configurations = [project.configurations.desktopRuntime]
jfxmobile
downConfig
version = '3.8.0'
// Do not edit the line below. Use Gluon Mobile Settings in your project context menu instead
plugins 'display', 'lifecycle', 'statusbar', 'storage'
android
manifest = 'src/android/AndroidManifest.xml'
ios
infoPList = file('src/ios/Default-Info.plist')
forceLinkClasses = [
'com.khmerdev.**.*',
'com.gluonhq.**.*',
'javax.annotations.**.*',
'javax.inject.**.*',
'javax.json.**.*',
'org.glassfish.json.**.*'
]
日志
3:43:02 PM: Executing task 'launchIPadSimulator'...
The CompileOptions.bootClasspath property has been deprecated and is scheduled to be removed in Gradle 5.0. Please use the CompileOptions.bootstrapClasspath property instead.
Note: /Users/sovandara/Documents/KhmerDEV/Project/cashmag/source_code/contactapp/ContactApp/src/main/java/com/khmerdev/sample/H2app.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: /Users/sovandara/Documents/KhmerDEV/Project/cashmag/source_code/contactapp/ContactApp/src/main/java/com/khmerdev/sample/H2app.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
:ContactApp:compileJava
:ContactApp:processResources UP-TO-DATE
:ContactApp:classes
:ContactApp:createDefaultIOSLauncher UP-TO-DATE
:ContactApp:compileIosJava UP-TO-DATE
:ContactApp:processIosResources NO-SOURCE
:ContactApp:iosClasses UP-TO-DATE
:ContactApp:iosExtractNativeLibs UP-TO-DATE
:ContactApp:launchIPadSimulator
Root pattern javax.annotations.**.* matches no classes
Root pattern javax.inject.**.* matches no classes
javax.xml.stream.XMLEventFactory=com.sun.xml.stream.events.ZephyrEvent...
java.vendor.url=http://www.robovm.org/
java.ext.dirs=
line.separator=
file.encoding=UTF-8
java.runtime.version=0.9
user.name=mobile
java.compiler=
prism.static.libraries=true
android.icu.unicode.version=6.2
javax.xml.stream.XMLOutputFactory=com.sun.xml.stream.ZephyrWriterFactory
java.version=0
android.icu.library.version=51.1.0.1
os.arch=x86_64
java.io.tmpdir=/Users/sovandara/Library/Developer/Co...
glass.platform=ios
android.zlib.version=1.2.8
user.language=en
java.vm.version=2.3.1-ios11
com.sun.javafx.isEmbedded=true
javax.xml.stream.XMLInputFactory=com.sun.xml.stream.ZephyrParserFactory
path.separator=:
java.runtime.name=RoboVM Runtime
java.specification.version=0.9
user.dir=/Users/sovandara/Library/Developer/Co...
java.vm.specification.vendor=RoboVM
java.vm.name=RoboVM
java.vm.specification.version=0.9
prism.useNativeIIO=false
user.home=/Users/sovandara/Library/Developer/Co...
jfxmedia.platforms=IOSPlatform
java.specification.name=RoboVM Core Library
file.separator=/
user.variant=
os.version=10.13.5
java.boot.class.path=/Users/sovandara/Library/Developer/Co...
java.vm.specification.name=RoboVM Virtual Machine Specification
javafx.platform=ios
user.region=US
os.name=iOS Simulator
java.class.path=/Users/sovandara/Library/Developer/Co...
prism.verbose=true
java.specification.vendor=RoboVM
java.vm.vendor=RoboVM
prism.mintexturesize=16
prism.allowhidpi=true
java.vendor=RoboVM
android.icu.cldr.version=23.1
android.openssl.version=OpenSSL 1.0.1e 11 Feb 2013
java.home=/Users/sovandara/Library/Developer/Co...
java.vm.vendor.url=http://www.robovm.org/
java.class.version=50.0
Prism pipeline init order: es2
Using native-based Pisces rasterizer
Using dirty region optimizations
Using system sized mask for primitives
Not forcing power of 2 sizes for textures
Using hardware CLAMP_TO_ZERO mode
Opting in for HiDPI pixel scaling
Prism pipeline name = com.sun.prism.es2.ES2Pipeline
Loading ES2 native library ... prism_es2
succeeded.
GLFactory using com.sun.prism.es2.IOSGLFactory
IOSWindowSystemInterface : share 0 view 0 pf otready
GL_VERSION string = OpenGL ES 2.0 APPLE-16.4.2
GL_VERSION (major.minor) = 0.0
initialize() returns 140384845988192
(X) Got class = class com.sun.prism.es2.ES2Pipeline
Initialized prism pipeline: com.sun.prism.es2.ES2Pipeline
IOSWindowSystemInterface : share 271e0 view 0 pf otready
GL_VERSION string = OpenGL ES 2.0 APPLE-16.4.2
GL_VERSION (major.minor) = 0.0
CTXINFO vendor
CTXINFO renderer
CTXINFO glExtensions
CTXINFO GL_ARB_pixel_buffer_object
CTXINFO allocate the structure
CTXINFO set function pointers
Attributes = onScreen: trueredSize : 8, greenSize : 8, blueSize : 8, alphaSize : 8, depthSize : 24, doubleBuffer : true
initialize() returns 140384843884416
IOSWindowSystemInterface : share 271e0 view 0 pf otready
GL_VERSION string = OpenGL ES 2.0 APPLE-16.4.2
GL_VERSION (major.minor) = 0.0
CTXINFO vendor
CTXINFO renderer
CTXINFO glExtensions
CTXINFO GL_ARB_pixel_buffer_object
CTXINFO allocate the structure
CTXINFO set function pointers
Attributes = onScreen: trueredSize : 8, greenSize : 8, blueSize : 8, alphaSize : 8, depthSize : 24, doubleBuffer : true
initialize() returns 140384847044992
Maximum supported texture size: 4096
Non power of two texture support = false
Maximum number of vertex attributes = 16
Maximum number of uniform vertex components = 512
Maximum number of uniform fragment components = 256
Maximum number of varying components = 32
Maximum number of texture units usable in a vertex shader = 8
Maximum number of texture units usable in a fragment shader = 8
Graphics Vendor: Apple Inc.
Renderer: Apple Software Renderer
Version: OpenGL ES 2.0 APPLE-16.4.2
vsync: true vpipe: true
[WARN] java.lang.Class: Class.forName() failed to load 'com.sun.javafx.font.t2k.T2KFactory'. Use the -forcelinkclasses command line option or add <forceLinkClasses><pattern>com.sun.javafx.font.t2k.T2KFactory</pattern></forceLinkClasses> to your robovm.xml file to link it in.
2018-07-12 15:44:22.410 ContactApp[12971:469616] Done creating private storage /Users/sovandara/Library/Developer/CoreSimulator/Devices/6B6CA6F1-290F-4BC2-BAF3-47DEDD738A4A/data/Containers/Data/Application/A69488DB-53AA-4833-9BA8-E07EDDF44C46/Library/gluon
[WARN] java.lang.Class: Class.forName() failed to load 'javax.xml.stream.FactoryFinder$ClassLoaderFinderConcrete'. Use the -forcelinkclasses command line option or add <forceLinkClasses><pattern>javax.xml.stream.FactoryFinder$ClassLoaderFinderConcrete</pattern></forceLinkClasses> to your robovm.xml file to link it in.
Jul 12, 2018 3:44:22 PM java.util.logging.LoggingProxyImpl log
WARNING: Loading FXML document with JavaFX API of version 10.0.1 by JavaFX runtime of version 8.0.72-ea
path=/Users/sovandara/Library/Developer/CoreSimulator/Devices/6B6CA6F1-290F-4BC2-BAF3-47DEDD738A4A/data/Containers/Data/Application/A69488DB-53AA-4833-9BA8-E07EDDF44C46/Library/gluon
dbUrl=jdbc:h2:/Users/sovandara/Library/Developer/CoreSimulator/Devices/6B6CA6F1-290F-4BC2-BAF3-47DEDD738A4A/data/Containers/Data/Application/A69488DB-53AA-4833-9BA8-E07EDDF44C46/Library/gluon/CONTACT;FILE_LOCK=FS;PAGE_SIZE=1024;CACHE_SIZE=8192
getConnection=
[WARN] java.lang.Class: Class.forName() failed to load 'org.h2.upgrade.v1_1.Driver'. Use the -forcelinkclasses command line option or add <forceLinkClasses><pattern>org.h2.upgrade.v1_1.Driver</pattern></forceLinkClasses> to your robovm.xml file to link it in.
IOException: javafx.fxml.LoadException:
file:/Users/sovandara/Library/Developer/CoreSimulator/Devices/6B6CA6F1-290F-4BC2-BAF3-47DEDD738A4A/data/Containers/Bundle/Application/AA0E7D96-ED31-4898-B6D8-05E7DD037568/ContactApp.app/lib/classes28.jar!/com/khmerdev/views/contact.fxml
[WARN] java.lang.Class: Class.forName() failed to load 'com.sun.javafx.tk.quantum.QuantumMessagesBundle_en_US'. Use the -forcelinkclasses command line option or add <forceLinkClasses><pattern>com.sun.javafx.tk.quantum.QuantumMessagesBundle_en_US</pattern></forceLinkClasses> to your robovm.xml file to link it in.
[WARN] java.lang.Class: Class.forName() failed to load 'com.sun.javafx.tk.quantum.QuantumMessagesBundle_en'. Use the -forcelinkclasses command line option or add <forceLinkClasses><pattern>com.sun.javafx.tk.quantum.QuantumMessagesBundle_en</pattern></forceLinkClasses> to your robovm.xml file to link it in.
[WARN] java.lang.Class: Class.forName() failed to load 'com.sun.javafx.tk.quantum.QuantumMessagesBundle'. Use the -forcelinkclasses command line option or add <forceLinkClasses><pattern>com.sun.javafx.tk.quantum.QuantumMessagesBundle</pattern></forceLinkClasses> to your robovm.xml file to link it in.
[WARN] java.lang.Class: Class.forName() failed to load 'com.oracle.jrockit.jfr.FlightRecorder'. Use the -forcelinkclasses command line option or add <forceLinkClasses><pattern>com.oracle.jrockit.jfr.FlightRecorder</pattern></forceLinkClasses> to your robovm.xml file to link it in.
setSwapInterval(1)
max rectangle texture cell size = 89
wrap rectangle texture = 2 x 2
ES2ResourceFactory: Prism - createStockShader: AlphaTexture_Color.frag
PPSRenderer: scenario.effect - createShader: LinearConvolveShadow_20
ES2ResourceFactory: Prism - createStockShader: Solid_TextureRGB.frag
Growing pool ES2 Vram Pool target to 73,400,324
Growing pool ES2 Vram Pool target to 88,080,388
ES2ResourceFactory: Prism - createStockShader: Texture_Color.frag
Growing pool ES2 Vram Pool target to 97,533,956
PPSRenderer: scenario.effect - createShader: LinearConvolveShadow_64
Growing pool ES2 Vram Pool target to 105,922,564
setSwapInterval(0)
setSwapInterval(1)
setSwapInterval(0)
setSwapInterval(1)
Growing pool ES2 Vram Pool target to 117,211,140
PPSRenderer: scenario.effect - createShader: LinearConvolve_16
请查看以下截图
Window
Tablet
Mac
iPad
【问题讨论】:
尝试将'org.h2.**.*'
添加到您的build.gradle 文件的forceLinkClasses
选项中。
它不工作,它显示相同的错误。我也试试看:(
【参考方案1】:
当您在 iOS 上运行 H2 时,问题与 forceLinkClasses
无关(可能无论如何都需要),而是与 javax.management
包的缺少实现有关,正如您将在日志中看到的那样:
java.lang.NoClassDefFoundError: java/lang/management/ManagementFactory
这意味着 Java 包的 RoboVM 实现没有添加 java.lang.management
/ javax.management
类。
由于 H2 是开源的,您可以删除 JMX 引用并使用您的自定义构建,或者我们可以尝试绕过 iOS 上的问题,提供缺失类的虚拟实现。
我只测试了GluonSQLite 示例(但使用 H2 而不是 SQLite),添加了这两个类:
java.lang.management.ManagementFactory
package java.lang.management;
import java.util.ArrayList;
import java.util.List;
import javax.management.MBeanServer;
import javax.management.ThreadMXBean;
import javax.management.GarbageCollectorMXBean;
public class ManagementFactory
public static synchronized MBeanServer getPlatformMBeanServer()
return new MBeanServer();
public static ThreadMXBean getThreadMXBean()
return new ThreadMXBean();
public static List<GarbageCollectorMXBean> getGarbageCollectorMXBeans()
return new ArrayList<>();
public static OperatingSystemMXBean getOperatingSystemMXBean()
return new OperatingSystemMXBean();
java.lang.managementOperatingSystemMXBean
package java.lang.management;
public class OperatingSystemMXBean
public String getName()
return "";
public String getArch()
return "";
public String getVersion()
return "";
public int getAvailableProcessors()
return 0;
public double getSystemLoadAverage()
return 0;
还有这三个空类:
package javax.management;
public class GarbageCollectorMXBean
package javax.management;
public class MBeanServer
package javax.management;
public class ThreadMXBean
其中包括:'org.h2.**.*'
和 'javax.management.**.*'
在 build.gradle 文件中强制使用LinkClasses,该示例在 iOS 上成功运行(H2 连接、数据库创建、插入、选择......)。
【讨论】:
以上是关于当我使用 H2 数据库作为嵌入式时,Gluon 应用程序无法在 ios 上加载 FXML的主要内容,如果未能解决你的问题,请参考以下文章