在使用 maven-asssembly 插件打包的单 jar 应用程序中,我无法让 hibernate 与 yGuard 很好地配合。应用程序在尝试创建实体管理器时无法初始化数据库连接。
运行使用 Maven 程序集插件创建的非混淆 jar 运行得很好。此外,使用外部
lib/
目录运行多文件 jar 效果很好。当我尝试创建一个也被混淆的单个 jar 时,我遇到了持久性问题。
有人可以看一下我的 yGuard 和 hibernate 配置来帮助我找出为什么混淆的 jar 无法正确连接到数据库吗?
这是我尝试过的:
<keep>
标签混淆我的持久层persistence.xml
切换到编程式休眠配置应用程序启动,但在初始化我的
Database
实用程序类时无法创建数据库连接:
public class Database {
private static SessionFactory factory;
static {
Configuration configuration = new Configuration();
configuration.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
configuration.setProperty("hibernate.hbm2ddl.auto", "update");
configuration.setProperty("javax.persistence.jdbc.driver", "org.h2.driver");
configuration.setProperty("javax.persistence.jdbc.url",
"jdbc:h2:file:./hyperaccsdb");
configuration.addAnnotatedClass(Account.class);
configuration.addAnnotatedClass(AccountCookie.class);
configuration.addAnnotatedClass(EmailAccount.class);
configuration.addAnnotatedClass(EmailInbox.class);
configuration.addAnnotatedClass(EmailPlatform.class);
configuration.addAnnotatedClass(Avatar.class);
configuration.addAnnotatedClass(BrowserConfig.class);
factory = configuration.buildSessionFactory();
}
public static EntityManager getEntityManager() {
return factory.createEntityManager();
}
}
这是我在尝试初始化数据库连接时得到的堆栈跟踪:
Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: Could not initialize class com.toughdata.autogrowth.persistence.Database 13:36:54 [41/1289]
at com.toughdata.autogrowth.persistence.dao.EmailPlatformDaoImpl.A(Unknown Source)
at com.toughdata.autogrowth.B.F.A(Unknown Source)
at com.toughdata.autogrowth.B.R.A(Unknown Source)
at com.toughdata.autogrowth.C.M.A(Unknown Source)
at com.toughdata.autogrowth.C.I.D(Unknown Source)
at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1972)
at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2313)
at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:279)
at java.desktop/java.awt.Component.processMouseEvent(Component.java:6626)
at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3389)
at java.desktop/java.awt.Component.processEvent(Component.java:6391)
at java.desktop/java.awt.Container.processEvent(Container.java:2266)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5001)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4833)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4948)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4575)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4516)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2310)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2780)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4833)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:775)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:747)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:744)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.ExceptionInInitializerError [in thread "SwingWorker-pool-2-thread-1"]
at net.bytebuddy.implementation.bind.MethodDelegationBinder$AmbiguityResolver.<clinit>(Unknown Source)
at net.bytebuddy.implementation.MethodDelegation.L(Unknown Source)
at net.bytebuddy.implementation.MethodDelegation.B(Unknown Source)
at org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState$ProxyDefinitionHelpers$1.A(Unknown Source)
at org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState$ProxyDefinitionHelpers$1.run(Unknown Source)
at org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState$ProxyDefinitionHelpers.<init>(Unknown Source)
at org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState.<clinit>(Unknown Source)
at org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl.<init>(Unknown Source)
at org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl.<init>(Unknown Source)
at org.hibernate.bytecode.internal.BytecodeProviderInitiator.A(Unknown Source)
at org.hibernate.bytecode.internal.BytecodeProviderInitiator.W(Unknown Source)
at org.hibernate.bytecode.internal.BytecodeProviderInitiator.A(Unknown Source)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.A(Unknown Source)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.F(Unknown Source)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.G(Unknown Source)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.A(Unknown Source)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.<init>(Unknown Source)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.<init>(Unknown Source)
at org.hibernate.boot.internal.DefaultSessionFactoryBuilderService.A(Unknown Source)
at org.hibernate.boot.internal.MetadataImpl.ʦ(Unknown Source)
at org.hibernate.cfg.Configuration.B(Unknown Source)
at org.hibernate.cfg.Configuration.C(Unknown Source)
at com.toughdata.autogrowth.persistence.Database.<clinit>(Unknown Source)
at com.toughdata.autogrowth.persistence.dao.EmailPlatformDaoImpl.B(Unknown Source)
at com.toughdata.autogrowth.B.O.A(Unknown Source)
at com.toughdata.autogrowth.B.R.A(Unknown Source)
at com.toughdata.autogrowth.C.M.A(Unknown Source)
at com.toughdata.autogrowth.C.I$1.A(Unknown Source)
at com.toughdata.autogrowth.C.I$1.doInBackground(Unknown Source)
at java.desktop/javax.swing.SwingWorker$1.call(SwingWorker.java:304)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.desktop/javax.swing.SwingWorker.run(SwingWorker.java:343)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:840)
这是我的
yGuard
蚂蚁任务:
<yguard>
<inoutpair in="${project.jar.unobf}" out="${project.jar}" />
<rename
logfile="${project.build.directory}/${project.build.finalName}_renamelog.xml">
<adjust replacePath="false">
<include name="/resources/*" />
</adjust>
<adjust replaceContent="true" replaceContentSeparator=".">
<include name="**/*.xml" />
<include name="**/*.dll" />
<include name="**/*.so" />
</adjust>
<keep>
<method name="void main(java.lang.String[])"
class="${mainclass}" />
<class>
<patternset>
<include name="**.*" />
<exclude name="com.toughdata.autogrowth.gui.*" />
<exclude
name="com.toughdata.autogrowth.automation.**.*" />
<exclude
name="com.toughdata.autogrowth.commands.**.*" />
<exclude name="com.toughdata.autogrowth.auth.*" />
</patternset>
</class>
<field name="*">
<patternset>
<include
name="com.toughdata.autogrowth.persistence.entities.*" />
</patternset>
</field>
<field
class="org.apache.logging.log4j.core.config.AppenderControlArraySet"
name="appenderArray" />
<field
class="com.toughdata.autogrowth.persistence.Database"
name="factory" />
</keep>
</rename>
</yguard>
编辑: 查看 yGuard 的重命名日志,我可以看到 Hibernate 类由于某种原因被重命名。我将向其中添加一条保留规则,看看会发生什么。我认为我的模式
**.*
应该排除它们,但也许我需要更具体。这是重命名日志的片段:
<method class="org.hibernate.StaleObjectStateException" name="java.lang.String getEntityName()" map="£"/>
<method class="org.hibernate.Metamodel" name="java.lang.String[] getImplementors(java.lang.String)" map="ó"/>
<field class="org.hibernate.UnknownProfileException" name="name" map="À"/>
<method class="org.hibernate.UnknownProfileException" name="java.lang.String getName()" map="¤"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy$AttributeInformation" name="org.hibernate.type.Type getType()" map="A"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy$AttributeInformation" name="java.lang.Object getLoadedValue()" map="B"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy$AttributeInformation" name="java.lang.String getName()" map="C"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy$AttributeInformation" name="int getAttributeIndex()" map="D"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy$AttributeInformation" name="org.hibernate.persister.entity.EntityPersister getContainingPersister()" map="E"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy$AttributeInformation" name="java.lang.Object getCurrentValue()" map="F"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy$AttributeChecker" name="boolean isDirty(org.hibernate.CustomEntityDirtinessStrategy$AttributeInformation)" map="A"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy$DirtyCheckContext" name="void doDirtyChecking(org.hibernate.CustomEntityDirtinessStrategy$AttributeChecker)" map="A"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy" name="boolean canDirtyCheck(java.lang.Object, org.hibernate.persister.entity.EntityPersister, org.hibernate.Session)" map="A"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy" name="boolean isDirty(java.lang.Object, org.hibernate.persister.entity.EntityPersister, org.hibernate.Session)" map="B"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy" name="void resetDirty(java.lang.Object, org.hibernate.persister.entity.EntityPersister, org.hibernate.Session)" map="C"/>
<method class="org.hibernate.CustomEntityDirtinessStrategy" name="void findDirty(java.lang.Object, org.hibernate.persister.entity.EntityPersister, org.hibernate.Session, org.hibernate.CustomEntityDirtinessStrategy$DirtyCheckContext)" map="A"/>
<class name="org.hibernate.CacheMode$1" map="1"/>
<field class="org.hibernate.CacheMode$1" name="$SwitchMap$jakarta$persistence$CacheStoreMode" map="A"/>
<field class="org.hibernate.CacheMode$1" name="$SwitchMap$jakarta$persistence$CacheRetrieveMode" map="B"/>
<field class="org.hibernate.CacheMode" name="REFRESH" map="A"/>
<field class="org.hibernate.CacheMode" name="GET" map="B"/>
<field class="org.hibernate.CacheMode" name="retrieveMode" map="C"/>
<field class="org.hibernate.CacheMode" name="$VALUES" map="D"/>
<field class="org.hibernate.CacheMode" name="PUT" map="E"/>
<field class="org.hibernate.CacheMode" name="NORMAL" map="F"/>
<field class="org.hibernate.CacheMode" name="storeMode" map="G"/>
<field class="org.hibernate.CacheMode" name="IGNORE" map="H"/>
<method class="org.hibernate.CacheMode" name="boolean isGetEnabled()" map="A"/>
<method class="org.hibernate.CacheMode" name="org.hibernate.CacheMode interpretExternalSetting(java.lang.String)" map="A"/>
<method class="org.hibernate.CacheMode" name="jakarta.persistence.CacheStoreMode getJpaStoreMode()" map="B"/>
<method class="org.hibernate.CacheMode" name="org.hibernate.CacheMode[] values()" map="values"/>
<method class="org.hibernate.CacheMode" name="boolean isPutEnabled()" map="C"/>
<method class="org.hibernate.CacheMode" name="org.hibernate.CacheMode fromJpaModes(jakarta.persistence.CacheRetrieveMode, jakarta.persistence.CacheStoreMode)" map="A"/>
<method class="org.hibernate.CacheMode" name="org.hibernate.CacheMode valueOf(java.lang.String)" map="valueOf"/>
<method class="org.hibernate.CacheMode" name="jakarta.persistence.CacheRetrieveMode getJpaRetrieveMode()" map="D"/>
<field class="org.hibernate.TransientPropertyValueException" name="propertyName" map="i"/>
<field class="org.hibernate.TransientPropertyValueException" name="transientEntityName" map="j"/>
<field class="org.hibernate.TransientPropertyValueException" name="propertyOwnerEntityName" map="k"/>
<method class="org.hibernate.TransientPropertyValueException" name="java.lang.String getMessage()" map="getMessage"/>
<method class="org.hibernate.TransientPropertyValueException" name="java.lang.String getPropertyOwnerEntityName()" map="a"/>
<method class="org.hibernate.TransientPropertyValueException" name="java.lang.String getTransientEntityName()" map="b"/>
<method class="org.hibernate.TransientPropertyValueException" name="java.lang.String getPropertyName()" map="c"/>
<field class="org.hibernate.LazyInitializationException" name="LOG" map="Á"/>
<method class="org.hibernate.SessionFactoryObserver" name="void sessionFactoryCreated(org.hibernate.SessionFactory)" map="A"/>
<method class="org.hibernate.SessionFactoryObserver" name="void sessionFactoryClosing(org.hibernate.SessionFactory)" map="B"/>
<method class="org.hibernate.SessionFactoryObserver" name="void sessionFactoryClosed(org.hibernate.SessionFactory)" map="C"/>
</map>
看来我的问题来自于对 yGuard 的 keep 流程缺乏了解。查看keep日志后,我注意到Hibernate中的所有类名都被保留,但所有方法和字段都在改变。我最初的假设是,因为我保留了类,所以字段和方法也会保留。不是这种情况。当告诉 yGuard 保留外部库中的类时,您必须显式指定要保留的方法和字段的可见性。
以下是需要定义保留规则的方式:
<keep>
<class methods="public" fields="public">
<patternset>
<include name="com.my.pattern.to.keep.*" />
</patternset>
</class>
</keep>
</keep>
这一切都在 yGuard 文档的
class
部分进行了解释:https://yworks.github.io/yGuard/task_documentation.html#the-class-element