From 92c5d4d8dd1af5d81218534bd3c8cfe49c703496 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sun, 28 Jan 2024 01:12:47 +0100 Subject: [PATCH] Split Native Runtime Hints generation in appropriate packages + try to register types using the mappings.xml --- .github/workflows/graal-native.yml | 33 ++ .../impl/aot/FlowableAppRuntimeHints.java | 31 ++ .../resources/META-INF/spring/aot.factories | 2 + .../aot/FlowableBatchServiceRuntimeHints.java | 31 ++ .../resources/META-INF/spring/aot.factories | 2 + .../impl/aot/FlowableCmmnRuntimeHints.java | 38 +++ .../resources/META-INF/spring/aot.factories | 2 + .../impl/aot/FlowableDmnRuntimeHints.java | 32 ++ .../resources/META-INF/spring/aot.factories | 2 + .../impl/aot/FlowableCommonRuntimeHints.java | 39 +++ ...FlowableMyBatisResourceHintsRegistrar.java | 106 ++++++ .../impl/aot/FlowableMyBatisRuntimeHints.java | 73 +++++ .../FlowableSqlResourceHintsRegistrar.java | 31 ++ .../resources/META-INF/spring/aot.factories | 3 + .../impl/aot/FlowableProcessRuntimeHints.java | 39 +++ .../resources/META-INF/spring/aot.factories | 2 + ...FlowableEntityLinkServiceRuntimeHints.java | 31 ++ .../resources/META-INF/spring/aot.factories | 2 + .../FlowableEventRegistryRuntimeHints.java | 41 +++ .../resources/META-INF/spring/aot.factories | 2 + ...eEventSubscriptionServiceRuntimeHints.java | 30 ++ .../resources/META-INF/spring/aot.factories | 3 + ...owableIdentityLinkServiceRuntimeHints.java | 30 ++ .../resources/META-INF/spring/aot.factories | 2 + .../aot/FlowableJobServiceRuntimeHints.java | 30 ++ .../resources/META-INF/spring/aot.factories | 2 + .../native.sh | 2 +- .../pom.xml | 121 ++++++- .../src/main/resources/application.properties | 1 - ...BeanFactoryInitializationAotProcessor.java | 304 ------------------ ...BeanFactoryInitializationAotProcessor.java | 38 --- .../spring/aot/FlowableSpringAotUtils.java | 85 ----- ...BeanFactoryInitializationAotProcessor.java | 169 ---------- ...BeanFactoryInitializationAotProcessor.java | 262 --------------- .../spring/aot/MybatisMapperTypeUtils.java | 63 ---- ...BeanFactoryInitializationAotProcessor.java | 133 -------- .../BaseAutoDeployResourceContribution.java | 100 ++++++ ...BeanFactoryInitializationAotProcessor.java | 122 +++++++ ...BeanFactoryInitializationAotProcessor.java | 63 ++++ ...BeanFactoryInitializationAotProcessor.java | 122 +++++++ ...DefaultPropertiesLocationRuntimeHints.java | 65 ++++ .../resources/META-INF/spring/aot.factories | 10 +- .../aot/FlowableTaskServiceRuntimeHints.java | 30 ++ .../resources/META-INF/spring/aot.factories | 2 + .../FlowableVariableServiceRuntimeHints.java | 34 ++ .../resources/META-INF/spring/aot.factories | 2 + pom.xml | 7 + 47 files changed, 1312 insertions(+), 1062 deletions(-) create mode 100644 .github/workflows/graal-native.yml create mode 100644 modules/flowable-app-engine/src/main/java/org/flowable/app/engine/impl/aot/FlowableAppRuntimeHints.java create mode 100644 modules/flowable-app-engine/src/main/resources/META-INF/spring/aot.factories create mode 100644 modules/flowable-batch-service/src/main/java/org/flowable/batch/service/impl/aot/FlowableBatchServiceRuntimeHints.java create mode 100644 modules/flowable-batch-service/src/main/resources/META-INF/spring/aot.factories create mode 100644 modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/aot/FlowableCmmnRuntimeHints.java create mode 100644 modules/flowable-cmmn-engine/src/main/resources/META-INF/spring/aot.factories create mode 100644 modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/aot/FlowableDmnRuntimeHints.java create mode 100644 modules/flowable-dmn-engine/src/main/resources/META-INF/spring/aot.factories create mode 100644 modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableCommonRuntimeHints.java create mode 100644 modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableMyBatisResourceHintsRegistrar.java create mode 100644 modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableMyBatisRuntimeHints.java create mode 100644 modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableSqlResourceHintsRegistrar.java create mode 100644 modules/flowable-engine-common/src/main/resources/META-INF/spring/aot.factories create mode 100644 modules/flowable-engine/src/main/java/org/flowable/engine/impl/aot/FlowableProcessRuntimeHints.java create mode 100644 modules/flowable-engine/src/main/resources/META-INF/spring/aot.factories create mode 100644 modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/aot/FlowableEntityLinkServiceRuntimeHints.java create mode 100644 modules/flowable-entitylink-service/src/main/resources/META-INF/spring/aot.factories create mode 100644 modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/aot/FlowableEventRegistryRuntimeHints.java create mode 100644 modules/flowable-event-registry/src/main/resources/META-INF/spring/aot.factories create mode 100644 modules/flowable-eventsubscription-service/src/main/java/org/flowable/eventsubscription/service/impl/aot/FlowableEventSubscriptionServiceRuntimeHints.java create mode 100644 modules/flowable-eventsubscription-service/src/main/resources/META-INF/spring/aot.factories create mode 100644 modules/flowable-identitylink-service/src/main/java/org/flowable/identitylink/service/impl/aot/FlowableIdentityLinkServiceRuntimeHints.java create mode 100644 modules/flowable-identitylink-service/src/main/resources/META-INF/spring/aot.factories create mode 100644 modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/aot/FlowableJobServiceRuntimeHints.java create mode 100644 modules/flowable-job-service/src/main/resources/META-INF/spring/aot.factories delete mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableBeanFactoryInitializationAotProcessor.java delete mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableMybatisMappersBeanFactoryInitializationAotProcessor.java delete mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableSpringAotUtils.java delete mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisApplicationSpecificBeanFactoryInitializationAotProcessor.java delete mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisGlobalBeanFactoryInitializationAotProcessor.java delete mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisMapperTypeUtils.java delete mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisMappersBeanFactoryInitializationAotProcessor.java create mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/BaseAutoDeployResourceContribution.java create mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/cmmn/FlowableCmmnAutoDeployBeanFactoryInitializationAotProcessor.java create mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/dmn/FlowableDmnAutoDeployBeanFactoryInitializationAotProcessor.java create mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/process/FlowableProcessAutoDeployBeanFactoryInitializationAotProcessor.java create mode 100644 modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/environment/FlowableDefaultPropertiesLocationRuntimeHints.java create mode 100644 modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/aot/FlowableTaskServiceRuntimeHints.java create mode 100644 modules/flowable-task-service/src/main/resources/META-INF/spring/aot.factories create mode 100644 modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/aot/FlowableVariableServiceRuntimeHints.java create mode 100644 modules/flowable-variable-service/src/main/resources/META-INF/spring/aot.factories diff --git a/.github/workflows/graal-native.yml b/.github/workflows/graal-native.yml new file mode 100644 index 00000000000..82ffd221e6e --- /dev/null +++ b/.github/workflows/graal-native.yml @@ -0,0 +1,33 @@ +name: Flowable Graal Build + +on: + push: + branches: + - main + - 'flowable-release-*' + +env: + MAVEN_ARGS: >- + -B -V --no-transfer-progress + -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 + +jobs: + test_graal: + name: Linux Graal Native + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: graalvm/setup-graalvm@v1 + with: + java-version: 17 + distribution: graalvm + - name: Cache Maven Repository + uses: actions/cache@v3 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + - name: Install + run: ./mvnw install -Pdistro ${MAVEN_ARGS} -DskipTests=true -Dmaven.javadoc.skip=true + - name: Test + run: ./mvnw test -PnativeTest,native,distro,errorLogging ${MAVEN_ARGS} -Dmaven.test.redirectTestOutputToFile=false -pl modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native diff --git a/modules/flowable-app-engine/src/main/java/org/flowable/app/engine/impl/aot/FlowableAppRuntimeHints.java b/modules/flowable-app-engine/src/main/java/org/flowable/app/engine/impl/aot/FlowableAppRuntimeHints.java new file mode 100644 index 00000000000..76235896c78 --- /dev/null +++ b/modules/flowable-app-engine/src/main/java/org/flowable/app/engine/impl/aot/FlowableAppRuntimeHints.java @@ -0,0 +1,31 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.app.engine.impl.aot; + +import org.flowable.common.engine.impl.aot.FlowableMyBatisResourceHintsRegistrar; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableAppRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + resourceHints.registerPattern("org/flowable/app/db/liquibase/flowable-app-db-changelog.xml"); + FlowableMyBatisResourceHintsRegistrar.registerMappingResources("org/flowable/app/db/mapping", hints, classLoader); + } +} diff --git a/modules/flowable-app-engine/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-app-engine/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..4c43ba98c20 --- /dev/null +++ b/modules/flowable-app-engine/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.app.engine.impl.aot.FlowableAppRuntimeHints diff --git a/modules/flowable-batch-service/src/main/java/org/flowable/batch/service/impl/aot/FlowableBatchServiceRuntimeHints.java b/modules/flowable-batch-service/src/main/java/org/flowable/batch/service/impl/aot/FlowableBatchServiceRuntimeHints.java new file mode 100644 index 00000000000..baba6d34262 --- /dev/null +++ b/modules/flowable-batch-service/src/main/java/org/flowable/batch/service/impl/aot/FlowableBatchServiceRuntimeHints.java @@ -0,0 +1,31 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.batch.service.impl.aot; + +import org.flowable.common.engine.impl.aot.FlowableSqlResourceHintsRegistrar; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableBatchServiceRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + FlowableSqlResourceHintsRegistrar.registerSqlResources("org/flowable/batch/service/db", resourceHints); + + } +} diff --git a/modules/flowable-batch-service/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-batch-service/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..2a04bc04f27 --- /dev/null +++ b/modules/flowable-batch-service/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.batch.service.impl.aot.FlowableBatchServiceRuntimeHints diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/aot/FlowableCmmnRuntimeHints.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/aot/FlowableCmmnRuntimeHints.java new file mode 100644 index 00000000000..60821021edd --- /dev/null +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/aot/FlowableCmmnRuntimeHints.java @@ -0,0 +1,38 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.cmmn.engine.impl.aot; + +import org.flowable.common.engine.impl.aot.FlowableMyBatisResourceHintsRegistrar; +import org.flowable.variable.service.impl.QueryVariableValue; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableCmmnRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + FlowableMyBatisResourceHintsRegistrar.registerMappingResources("org/flowable/cmmn/db/mapping", hints, classLoader); + resourceHints.registerPattern("org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml"); + resourceHints.registerPattern("org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog-crdb.xml"); + resourceHints.registerPattern("org/flowable/impl/cmmn/parser/*.xsd"); + + hints.reflection() + .registerType(QueryVariableValue.class, MemberCategory.INVOKE_PUBLIC_METHODS); + } +} diff --git a/modules/flowable-cmmn-engine/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-cmmn-engine/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..092b938353d --- /dev/null +++ b/modules/flowable-cmmn-engine/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.cmmn.engine.impl.aot.FlowableCmmnRuntimeHints diff --git a/modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/aot/FlowableDmnRuntimeHints.java b/modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/aot/FlowableDmnRuntimeHints.java new file mode 100644 index 00000000000..f3c0e982531 --- /dev/null +++ b/modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/aot/FlowableDmnRuntimeHints.java @@ -0,0 +1,32 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.dmn.engine.impl.aot; + +import org.flowable.common.engine.impl.aot.FlowableMyBatisResourceHintsRegistrar; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableDmnRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + FlowableMyBatisResourceHintsRegistrar.registerMappingResources("org/flowable/dmn/db/mapping", hints, classLoader); + resourceHints.registerPattern("org/flowable/dmn/db/liquibase/flowable-dmn-db-changelog.xml"); + resourceHints.registerPattern("org/flowable/impl/dmn/parser/*.xsd"); + } +} diff --git a/modules/flowable-dmn-engine/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-dmn-engine/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..50cfebdb05a --- /dev/null +++ b/modules/flowable-dmn-engine/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.dmn.engine.impl.aot.FlowableDmnRuntimeHints diff --git a/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableCommonRuntimeHints.java b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableCommonRuntimeHints.java new file mode 100644 index 00000000000..05eb7abefe1 --- /dev/null +++ b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableCommonRuntimeHints.java @@ -0,0 +1,39 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.common.engine.impl.aot; + +import org.flowable.common.engine.impl.persistence.entity.ByteArrayRefTypeHandler; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableCommonRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + resourceHints.registerPattern("META-INF/services/liquibase.hub.HubService"); + resourceHints.registerPattern("META-INF/services/liquibase.license.LicenseService"); + resourceHints.registerResourceBundle("org.flowable.common.engine.impl.de.odysseus.el.misc.LocalStrings"); + // If we can detect which DB is being used we can perhaps register only the appropriate DB file + resourceHints.registerPattern("org/flowable/common/db/properties/*.properties"); + FlowableSqlResourceHintsRegistrar.registerSqlResources("org/flowable/common/db", resourceHints); + + hints.reflection() + .registerType(ByteArrayRefTypeHandler.class, MemberCategory.values()); + } +} diff --git a/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableMyBatisResourceHintsRegistrar.java b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableMyBatisResourceHintsRegistrar.java new file mode 100644 index 00000000000..9c63ad0f8ef --- /dev/null +++ b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableMyBatisResourceHintsRegistrar.java @@ -0,0 +1,106 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.common.engine.impl.aot; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.builder.xml.XMLMapperEntityResolver; +import org.apache.ibatis.parsing.XNode; +import org.apache.ibatis.parsing.XPathParser; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.ReflectionHints; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.TypeReference; +import org.springframework.core.io.ClassPathResource; + +/** + * Register the necessary resource hints for the Flowable SQL resources. + * + * @author Filip Hrisafov + */ +public class FlowableMyBatisResourceHintsRegistrar { + + public static void registerMappingResources(String baseFolder, RuntimeHints runtimeHints, ClassLoader classLoader) { + ResourceHints resourceHints = runtimeHints.resources(); + String mappingsPath = baseFolder + "/mappings.xml"; + ClassPathResource mappingsResource = new ClassPathResource(mappingsPath); + resourceHints.registerResource(mappingsResource); + try (InputStream mappingsStream = mappingsResource.getInputStream()) { + XPathParser parser = createParser(mappingsStream); + + List mappers = parser.evalNodes("/configuration/mappers/mapper"); + for (XNode mapper : mappers) { + registerMapper(mapper.getStringAttribute("resource"), runtimeHints, classLoader); + } + } catch (IOException e) { + throw new UncheckedIOException("Failed to read mappings " + mappingsPath, e); + } + } + + public static void registerMapper(String mapperPath, RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + ClassPathResource mapperResource = new ClassPathResource(mapperPath); + resourceHints.registerResource(mapperResource); + + ReflectionHints reflectionHints = hints.reflection(); + MemberCategory[] memberCategories = MemberCategory.values(); + try (InputStream mapperStream = mapperResource.getInputStream()) { + XPathParser parser = createParser(mapperStream); + XNode mapper = parser.evalNode("/mapper"); + // The xpath resolving is similar like what MyBatis does in XMLMapperBuilder#parse + for (XNode resultMap : mapper.evalNodes("/mapper/resultMap")) { + String type = resultMap.getStringAttribute("type"); + if (type != null) { + reflectionHints.registerType(TypeReference.of(type), memberCategories); + } + } + + for (XNode statement : mapper.evalNodes("select|insert|update|delete")) { + String parameterType = statement.getStringAttribute("parameterType"); + if (parameterType != null) { + if (parameterType.startsWith("org.flowable") || parameterType.startsWith("java.")) { + reflectionHints.registerType(TypeReference.of(parameterType), memberCategories); + } else if (parameterType.equals("map")) { + reflectionHints.registerType(Map.class, memberCategories); + } + } + + String resultType = statement.getStringAttribute("resultType"); + if (resultType != null) { + if (resultType.equals("long")) { + reflectionHints.registerType(long.class, memberCategories); + reflectionHints.registerType(Long.class, memberCategories); + } else if (resultType.equals("string")) { + reflectionHints.registerType(String.class, memberCategories); + } else if (resultType.equals("map")) { + reflectionHints.registerType(HashMap.class, memberCategories); + } + } + } + + } catch (IOException e) { + throw new UncheckedIOException("Failed to read mapper from " + mapperPath, e); + } + } + + protected static XPathParser createParser(InputStream stream) { + return new XPathParser(stream, false, null, new XMLMapperEntityResolver()); + } + +} diff --git a/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableMyBatisRuntimeHints.java b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableMyBatisRuntimeHints.java new file mode 100644 index 00000000000..06ad1a82183 --- /dev/null +++ b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableMyBatisRuntimeHints.java @@ -0,0 +1,73 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.common.engine.impl.aot; + +import org.apache.ibatis.cache.decorators.FifoCache; +import org.apache.ibatis.cache.decorators.LruCache; +import org.apache.ibatis.cache.decorators.SoftCache; +import org.apache.ibatis.cache.decorators.WeakCache; +import org.apache.ibatis.cache.impl.PerpetualCache; +import org.apache.ibatis.javassist.util.proxy.ProxyFactory; +import org.apache.ibatis.javassist.util.proxy.RuntimeSupport; +import org.apache.ibatis.logging.Log; +import org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl; +import org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl; +import org.apache.ibatis.logging.log4j2.Log4j2Impl; +import org.apache.ibatis.logging.nologging.NoLoggingImpl; +import org.apache.ibatis.logging.slf4j.Slf4jImpl; +import org.apache.ibatis.logging.stdout.StdOutImpl; +import org.apache.ibatis.scripting.defaults.RawLanguageDriver; +import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.ReflectionHints; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableMyBatisRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + // These hints are coming from https://github.com/mybatis/spring-boot-starter/wiki/MyBatisNativeConfiguration.java + MemberCategory[] memberCategories = MemberCategory.values(); + ReflectionHints reflectionHints = hints.reflection(); + reflectionHints.registerType(Configuration.class, memberCategories); + reflectionHints.registerType(RawLanguageDriver.class, memberCategories); + reflectionHints.registerType(XMLLanguageDriver.class, memberCategories); + reflectionHints.registerType(RuntimeSupport.class, memberCategories); + reflectionHints.registerType(ProxyFactory.class, memberCategories); + reflectionHints.registerType(Slf4jImpl.class, memberCategories); + reflectionHints.registerType(Log.class, memberCategories); + reflectionHints.registerType(JakartaCommonsLoggingImpl.class, memberCategories); + reflectionHints.registerType(Log4j2Impl.class, memberCategories); + reflectionHints.registerType(Jdk14LoggingImpl.class, memberCategories); + reflectionHints.registerType(StdOutImpl.class, memberCategories); + reflectionHints.registerType(NoLoggingImpl.class, memberCategories); + reflectionHints.registerType(SqlSessionFactory.class, memberCategories); + reflectionHints.registerType(PerpetualCache.class, memberCategories); + reflectionHints.registerType(FifoCache.class, memberCategories); + reflectionHints.registerType(LruCache.class, memberCategories); + reflectionHints.registerType(SoftCache.class, memberCategories); + reflectionHints.registerType(WeakCache.class, memberCategories); + + ResourceHints resourceHints = hints.resources(); + resourceHints.registerPattern("org/apache/ibatis/builder/xml/*.dtd"); + resourceHints.registerPattern("org/apache/ibatis/builder/xml/*.xsd"); + + } +} diff --git a/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableSqlResourceHintsRegistrar.java b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableSqlResourceHintsRegistrar.java new file mode 100644 index 00000000000..9fbf3c0f952 --- /dev/null +++ b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/aot/FlowableSqlResourceHintsRegistrar.java @@ -0,0 +1,31 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.common.engine.impl.aot; + +import java.util.stream.Stream; + +import org.springframework.aot.hint.ResourceHints; + +/** + * Register the necessary resource hints for the Flowable SQL resources. + * + * @author Filip Hrisafov + */ +public class FlowableSqlResourceHintsRegistrar { + + public static void registerSqlResources(String baseFolder, ResourceHints resourceHints) { + Stream.of("create", "drop", "upgrade") + .forEach(folder -> resourceHints.registerPattern(baseFolder + "/" + folder + "/*.sql")); + } + +} diff --git a/modules/flowable-engine-common/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-engine-common/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..019e315d926 --- /dev/null +++ b/modules/flowable-engine-common/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,3 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.common.engine.impl.aot.FlowableCommonRuntimeHints,\ +org.flowable.common.engine.impl.aot.FlowableMyBatisRuntimeHints diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/aot/FlowableProcessRuntimeHints.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/aot/FlowableProcessRuntimeHints.java new file mode 100644 index 00000000000..3c3f730eedc --- /dev/null +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/aot/FlowableProcessRuntimeHints.java @@ -0,0 +1,39 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.engine.impl.aot; + +import org.flowable.common.engine.impl.aot.FlowableMyBatisResourceHintsRegistrar; +import org.flowable.common.engine.impl.aot.FlowableSqlResourceHintsRegistrar; +import org.flowable.variable.service.impl.QueryVariableValue; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableProcessRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + resourceHints.registerPattern("META-INF/services/javax.script.ScriptEngineFactory"); + FlowableSqlResourceHintsRegistrar.registerSqlResources("org/flowable/db", resourceHints); + FlowableMyBatisResourceHintsRegistrar.registerMappingResources("org/flowable/db/mapping", hints, classLoader); + resourceHints.registerPattern("org/flowable/impl/bpmn/parser/*.xsd"); + + hints.reflection() + .registerType(QueryVariableValue.class, MemberCategory.INVOKE_PUBLIC_METHODS); + } +} diff --git a/modules/flowable-engine/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-engine/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..280667c77f0 --- /dev/null +++ b/modules/flowable-engine/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.engine.impl.aot.FlowableProcessRuntimeHints diff --git a/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/aot/FlowableEntityLinkServiceRuntimeHints.java b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/aot/FlowableEntityLinkServiceRuntimeHints.java new file mode 100644 index 00000000000..e2554e29758 --- /dev/null +++ b/modules/flowable-entitylink-service/src/main/java/org/flowable/entitylink/service/impl/aot/FlowableEntityLinkServiceRuntimeHints.java @@ -0,0 +1,31 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.entitylink.service.impl.aot; + +import org.flowable.common.engine.impl.aot.FlowableSqlResourceHintsRegistrar; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableEntityLinkServiceRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + FlowableSqlResourceHintsRegistrar.registerSqlResources("org/flowable/entitylink/service/db", resourceHints); + + } +} diff --git a/modules/flowable-entitylink-service/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-entitylink-service/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..05444f89a41 --- /dev/null +++ b/modules/flowable-entitylink-service/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.entitylink.service.impl.aot.FlowableEntityLinkServiceRuntimeHints diff --git a/modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/aot/FlowableEventRegistryRuntimeHints.java b/modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/aot/FlowableEventRegistryRuntimeHints.java new file mode 100644 index 00000000000..772beee6752 --- /dev/null +++ b/modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/aot/FlowableEventRegistryRuntimeHints.java @@ -0,0 +1,41 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.eventregistry.impl.aot; + +import java.util.Collections; + +import org.flowable.common.engine.impl.aot.FlowableMyBatisResourceHintsRegistrar; +import org.flowable.eventregistry.impl.db.SetChannelDefinitionTypeAndImplementationCustomChange; +import org.flowable.eventregistry.impl.persistence.ResourceRefTypeHandler; +import org.springframework.aot.hint.ExecutableMode; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableEventRegistryRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + FlowableMyBatisResourceHintsRegistrar.registerMappingResources("org/flowable/eventregistry/db/mapping", hints, classLoader); + resourceHints.registerPattern("org/flowable/eventregistry/db/liquibase/flowable-eventregistry-db-changelog.xml"); + hints.reflection() + .registerType(SetChannelDefinitionTypeAndImplementationCustomChange.class, + hint -> hint.withConstructor(Collections.emptyList(), ExecutableMode.INVOKE)) + .registerType(ResourceRefTypeHandler.class, MemberCategory.values()); + } +} diff --git a/modules/flowable-event-registry/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-event-registry/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..086d3dfa29e --- /dev/null +++ b/modules/flowable-event-registry/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.eventregistry.impl.aot.FlowableEventRegistryRuntimeHints diff --git a/modules/flowable-eventsubscription-service/src/main/java/org/flowable/eventsubscription/service/impl/aot/FlowableEventSubscriptionServiceRuntimeHints.java b/modules/flowable-eventsubscription-service/src/main/java/org/flowable/eventsubscription/service/impl/aot/FlowableEventSubscriptionServiceRuntimeHints.java new file mode 100644 index 00000000000..10626b2e586 --- /dev/null +++ b/modules/flowable-eventsubscription-service/src/main/java/org/flowable/eventsubscription/service/impl/aot/FlowableEventSubscriptionServiceRuntimeHints.java @@ -0,0 +1,30 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.eventsubscription.service.impl.aot; + +import org.flowable.common.engine.impl.aot.FlowableSqlResourceHintsRegistrar; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableEventSubscriptionServiceRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + FlowableSqlResourceHintsRegistrar.registerSqlResources("org/flowable/eventsubscription/service/db", resourceHints); + } +} diff --git a/modules/flowable-eventsubscription-service/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-eventsubscription-service/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..34decbb0ccf --- /dev/null +++ b/modules/flowable-eventsubscription-service/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,3 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.eventsubscription.service.impl.aot.FlowableEventSubscriptionServiceRuntimeHints + diff --git a/modules/flowable-identitylink-service/src/main/java/org/flowable/identitylink/service/impl/aot/FlowableIdentityLinkServiceRuntimeHints.java b/modules/flowable-identitylink-service/src/main/java/org/flowable/identitylink/service/impl/aot/FlowableIdentityLinkServiceRuntimeHints.java new file mode 100644 index 00000000000..3c33e7770a4 --- /dev/null +++ b/modules/flowable-identitylink-service/src/main/java/org/flowable/identitylink/service/impl/aot/FlowableIdentityLinkServiceRuntimeHints.java @@ -0,0 +1,30 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.identitylink.service.impl.aot; + +import org.flowable.common.engine.impl.aot.FlowableSqlResourceHintsRegistrar; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableIdentityLinkServiceRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + FlowableSqlResourceHintsRegistrar.registerSqlResources("org/flowable/identitylink/service/db", resourceHints); + } +} diff --git a/modules/flowable-identitylink-service/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-identitylink-service/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..e4a1a9f2cea --- /dev/null +++ b/modules/flowable-identitylink-service/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.identitylink.service.impl.aot.FlowableIdentityLinkServiceRuntimeHints diff --git a/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/aot/FlowableJobServiceRuntimeHints.java b/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/aot/FlowableJobServiceRuntimeHints.java new file mode 100644 index 00000000000..5205999a340 --- /dev/null +++ b/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/aot/FlowableJobServiceRuntimeHints.java @@ -0,0 +1,30 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.job.service.impl.aot; + +import org.flowable.common.engine.impl.aot.FlowableSqlResourceHintsRegistrar; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableJobServiceRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + FlowableSqlResourceHintsRegistrar.registerSqlResources("org/flowable/job/service/db", resourceHints); + } +} diff --git a/modules/flowable-job-service/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-job-service/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..df8363ddf25 --- /dev/null +++ b/modules/flowable-job-service/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.job.service.impl.aot.FlowableJobServiceRuntimeHints diff --git a/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/native.sh b/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/native.sh index 29a85ee759a..c4b829695e9 100755 --- a/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/native.sh +++ b/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/native.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash rm -rf target mvn -DskipTests -Pnative native:compile -./target/flowable +./target/flowable-spring-boot-sample-native diff --git a/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/pom.xml b/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/pom.xml index cbaa70290d7..a8ac3de9e60 100644 --- a/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/pom.xml +++ b/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/pom.xml @@ -15,9 +15,12 @@ org.flowable flowable-spring-boot-starter + - org.springframework.boot - spring-boot-starter-data-jpa + jakarta.persistence + jakarta.persistence-api org.springframework.boot @@ -33,6 +36,8 @@ --enable-url-protocols=https + --report-unsupported-elements-at-runtime + -H:+BuildReport @@ -49,4 +54,116 @@ + + + + native + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + paketobuildpacks/builder:tiny + + true + + + + + + process-aot + + process-aot + + + + + + org.graalvm.buildtools + native-maven-plugin + + ${project.build.outputDirectory} + + true + + 22.3 + + + + add-reachability-metadata + + add-reachability-metadata + + + + + + + + + + nativeTest + + + org.junit.platform + junit-platform-launcher + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + process-test-aot + + process-test-aot + + + + + + org.graalvm.buildtools + native-maven-plugin + + ${project.build.outputDirectory} + + true + + 22.3 + + + + native-test + + test + + + + + + + + + diff --git a/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/src/main/resources/application.properties b/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/src/main/resources/application.properties index 2740ffc144a..4ff7f396348 100644 --- a/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/src/main/resources/application.properties +++ b/modules/flowable-spring-boot/flowable-spring-boot-samples/flowable-spring-boot-sample-native/src/main/resources/application.properties @@ -4,6 +4,5 @@ logging.level.root=INFO spring.sql.init.mode=always -flowable.eventregistry.enabled=false flowable.idm.enabled=false flowable.jpa-enabled=false diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableBeanFactoryInitializationAotProcessor.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableBeanFactoryInitializationAotProcessor.java deleted file mode 100644 index 1316c0ee618..00000000000 --- a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableBeanFactoryInitializationAotProcessor.java +++ /dev/null @@ -1,304 +0,0 @@ -/* Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.flowable.spring.aot; - -import java.io.IOException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.apache.ibatis.javassist.util.proxy.ProxyFactory; -import org.apache.ibatis.scripting.defaults.RawLanguageDriver; -import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver; -import org.apache.ibatis.type.TypeHandler; -import org.flowable.bpmn.converter.BpmnXMLConverter; -import org.flowable.bpmn.model.ImplementationType; -import org.flowable.bpmn.model.ServiceTask; -import org.flowable.cmmn.converter.CmmnXmlConverter; -import org.flowable.common.engine.api.query.Query; -import org.flowable.common.engine.impl.db.ListQueryParameterObject; -import org.flowable.common.engine.impl.de.odysseus.el.ExpressionFactoryImpl; -import org.flowable.common.engine.impl.persistence.cache.EntityCacheImpl; -import org.flowable.common.engine.impl.persistence.entity.ByteArrayRef; -import org.flowable.common.engine.impl.persistence.entity.Entity; -import org.flowable.common.engine.impl.persistence.entity.EntityManager; -import org.flowable.common.engine.impl.persistence.entity.TablePageQueryImpl; -import org.flowable.eventregistry.impl.db.SetChannelDefinitionTypeAndImplementationCustomChange; -import org.flowable.variable.api.types.VariableType; -import org.flowable.variable.service.impl.InternalVariableInstanceQueryImpl; -import org.flowable.variable.service.impl.QueryVariableValue; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.aot.hint.MemberCategory; -import org.springframework.aot.hint.RuntimeHints; -import org.springframework.aot.hint.TypeReference; -import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; -import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.boot.autoconfigure.AutoConfigurationPackages; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * @author Josh Long - * @author Joram Barrez - */ -class FlowableBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor { - - private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); - - private final Logger log = LoggerFactory.getLogger(getClass()); - - FlowableBeanFactoryInitializationAotProcessor() { - } - - - private Set processResources() { - return resources("processes/**/*.bpmn20.xml", "processes/**/*.bpmn20"); - } - - private Set caseResources() { - return resources("cases/**/*.cmmn", "cases/**/*.cmmn.xml"); - } - - private Set ruleResources() { - return resources("dmn/**/*.dmn", "cases/**/*.dmn.xml"); - } - - private Set flowablePersistenceResources() throws Exception { - - var resources = new HashSet(); - resources.addAll(resources("org/flowable/**/*.sql", "org/flowable/**/*.xml", "org/flowable/**/*.txt", "org/flowable/**/*.xsd", "org/flowable/**/*.properties")); - - resources.addAll(processResources()); - resources.addAll(caseResources()); - resources.addAll(ruleResources()); - - for (var e : "xml,yaml,yml".split(",")) - resources.add(new ClassPathResource("flowable-default." + e)); - - resources.addAll(from(this.resolver.getResources("META-INF/services/org.flowable.common.engine.impl.EngineConfigurator"))); - resources.addAll(from(this.resolver.getResources("org/flowable/common/engine/impl/de/odysseus/el/misc/LocalStrings"))); - return resources.stream() - .filter(Resource::exists) - .collect(Collectors.toSet()); - } - - @Override - public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { - return (generationContext, beanFactoryInitializationCode) -> { - var hints = generationContext.getRuntimeHints(); - beanFactory.getBeanClassLoader(); - try { - - var memberCategories = MemberCategory.values(); - - - for (var c : Set.of(ProxyFactory.class, XMLLanguageDriver.class, - org.apache.ibatis.logging.slf4j.Slf4jImpl.class, EntityCacheImpl.class, - RawLanguageDriver.class, org.apache.ibatis.session.Configuration.class, HashSet.class)) - hints.reflection().registerType(c, memberCategories); - - var types = new Class[]{ - TypeHandler.class, - EntityManager.class, - Entity.class, - Query.class, - VariableType.class, - ListQueryParameterObject.class, - TablePageQueryImpl.class, - SetChannelDefinitionTypeAndImplementationCustomChange.class, - ByteArrayRef.class, - InternalVariableInstanceQueryImpl.class, - QueryVariableValue.class, - ExpressionFactoryImpl.class - }; - - var packagesSet = new HashSet(); - packagesSet.add("org.apache.ibatis"); - packagesSet.add("org.flowable"); - packagesSet.addAll(AutoConfigurationPackages.get(beanFactory)); - var packages = packagesSet.toArray(new String[0]); - - for (var t : types) { - hints.reflection().registerType(t, memberCategories); - var subTypes = FlowableSpringAotUtils.getSubTypesOf(t, packages); - for (var s : subTypes) { - if (StringUtils.hasText(s)) { - hints.reflection().registerType(TypeReference.of(s), memberCategories); - } - } - } - - var resources = new HashSet(); - resources.addAll(flowablePersistenceResources()); - resources.addAll(""" - flowable-default.properties - flowable-default.xml - flowable-default.yaml - flowable-default.yml - """ - .stripIndent() - .stripLeading() - .trim() - .lines() - .map(l -> l.strip().trim()) - .filter(l -> !l.isEmpty()) - .map(ClassPathResource::new) - .toList()); - - - for (var resource : resources) { - if (resource.exists()) { - hints.resources().registerResource(resource); - } - } - - - // here lay dragons; we're going to attempt to proactively register aot hints for beans referenced within definitions - registerAotHintsForReferencedBeans(beanFactory, hints); - - }// - catch (Throwable throwable) { - throw new RuntimeException(throwable); - } - }; - } - - private void registerAotHintsForReferencedBeans(ConfigurableListableBeanFactory beanFactory, RuntimeHints hints) throws IOException { - registerAotHintForProcessDefinitionBeans(beanFactory, hints); - registerAotHintForCaseDefinitionBeans(beanFactory, hints); - } - - protected void registerAotHintForProcessDefinitionBeans(ConfigurableListableBeanFactory beanFactory, RuntimeHints hints) throws IOException { - var processDefinitions = this.processResources(); - for (var processDefinitionXmlResource : processDefinitions) { - Assert.state(processDefinitionXmlResource.exists(), "the process definition file [" + processDefinitionXmlResource.getFilename() + - "] does not exist"); - - hints.resources().registerResource(processDefinitionXmlResource); - try (var in = processDefinitionXmlResource.getInputStream()) { - - var bpmnXMLConverter = new BpmnXMLConverter(); - var bpmnModel = bpmnXMLConverter.convertToBpmnModel(() -> in, false, false); - var serviceTasks = bpmnModel.getMainProcess().findFlowElementsOfType(ServiceTask.class); - for (var serviceTask : serviceTasks) { - if (serviceTask.getImplementationType().equals(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION)) { - var expression = serviceTask.getImplementation(); - var expressionWithoutDelimiters = expression.substring(2); - expressionWithoutDelimiters = expressionWithoutDelimiters.substring(0, expressionWithoutDelimiters.length() - 1); - var beanName = expressionWithoutDelimiters; - try { - var beanDefinition = beanFactory.getBeanDefinition(beanName); - hints.reflection().registerType(TypeReference.of(beanDefinition.getBeanClassName()), MemberCategory.values()); - - log.debug("registering hint for bean name [" + beanName + "]"); - } - catch (Throwable throwable) { - log.error("couldn't find bean named [" + beanName + "]"); - } - - } - } - } - } - } - - protected void registerAotHintForCaseDefinitionBeans(ConfigurableListableBeanFactory beanFactory, RuntimeHints hints) throws IOException { - var caseDefinitions = this.caseResources(); - for (var caseDefinitionXmlResource : caseDefinitions) { - Assert.state(caseDefinitionXmlResource.exists(), "the case definition file [" + caseDefinitionXmlResource.getFilename() + - "] does not exist"); - - hints.resources().registerResource(caseDefinitionXmlResource); - try (var in = caseDefinitionXmlResource.getInputStream()) { - - var cmmXmlConverter = new CmmnXmlConverter(); - var cmmnModel = cmmXmlConverter.convertToCmmnModel(() -> in, false, false); - var serviceTasks = cmmnModel.getPrimaryCase().findPlanItemDefinitionsOfType(org.flowable.cmmn.model.ServiceTask.class); - for (var serviceTask : serviceTasks) { - if (serviceTask.getImplementationType().equals(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION)) { - var expression = serviceTask.getImplementation(); - var expressionWithoutDelimiters = expression.substring(2); - expressionWithoutDelimiters = expressionWithoutDelimiters.substring(0, expressionWithoutDelimiters.length() - 1); - var beanName = expressionWithoutDelimiters; - try { - var beanDefinition = beanFactory.getBeanDefinition(beanName); - hints.reflection().registerType(TypeReference.of(beanDefinition.getBeanClassName()), MemberCategory.values()); - - log.debug("registering hint for bean name [" + beanName + "]"); - } - catch (Throwable throwable) { - log.error("couldn't find bean named [" + beanName + "]"); - } - - } - } - } - } - } - - private static Set from(T[] t) { - return new HashSet<>(Arrays.asList(t)); - } - - private static Resource newResourceFor(Resource in) { - try { - var marker = "jar!"; - var externalFormOfUrl = in.getURL().toExternalForm(); - if (externalFormOfUrl.contains(marker)) { - var rest = externalFormOfUrl.substring(externalFormOfUrl.lastIndexOf(marker) + marker.length()); - return new ClassPathResource(rest); - }// - else { - // ugh i think this only works for maven? what about gradle? - var classesSubstring = "classes/"; - var locationOfClassesInUrl = externalFormOfUrl.indexOf(classesSubstring); - if (locationOfClassesInUrl != -1) { - return new ClassPathResource(externalFormOfUrl.substring(locationOfClassesInUrl + classesSubstring.length())); - } - - } - - return in; - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - - Set resources(String... patterns) { - return Stream - .of(patterns) - .map(path -> ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + path) - .flatMap(p -> { - try { - return Stream.of(this.resolver.getResources(p)); - }// - catch (IOException e) { - throw new RuntimeException(e); - } - }) - .map(FlowableBeanFactoryInitializationAotProcessor::newResourceFor) - .filter(Resource::exists) - .collect(Collectors.toSet()); - } - - -} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableMybatisMappersBeanFactoryInitializationAotProcessor.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableMybatisMappersBeanFactoryInitializationAotProcessor.java deleted file mode 100644 index 668f4e8fac4..00000000000 --- a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableMybatisMappersBeanFactoryInitializationAotProcessor.java +++ /dev/null @@ -1,38 +0,0 @@ -/* Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.flowable.spring.aot; - -import java.util.ArrayList; -import java.util.List; - -import org.springframework.beans.factory.BeanFactory; - -/** - * @author Josh Long - */ -class FlowableMybatisMappersBeanFactoryInitializationAotProcessor - extends MybatisMappersBeanFactoryInitializationAotProcessor { - - FlowableMybatisMappersBeanFactoryInitializationAotProcessor() { - - } - - @Override - protected List getPackagesToScan(BeanFactory b) { - var defaults = super.getPackagesToScan(b); - var l = new ArrayList(); - l.add("org.flowable"); - l.addAll(defaults); - return l; - } -} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableSpringAotUtils.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableSpringAotUtils.java deleted file mode 100644 index 3c172cc771d..00000000000 --- a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/FlowableSpringAotUtils.java +++ /dev/null @@ -1,85 +0,0 @@ -/* Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.flowable.spring.aot; - -import java.io.IOException; -import java.io.Serializable; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.core.type.filter.AssignableTypeFilter; - -/** - * @author Josh Long - */ -final class FlowableSpringAotUtils { - - private static final Logger log = LoggerFactory.getLogger(FlowableSpringAotUtils.class); - - private FlowableSpringAotUtils() { - } - - static Resource newResourceFor(Resource in) { - try { - var marker = "jar!"; - var p = in.getURL().toExternalForm(); - var rest = p.substring(p.lastIndexOf(marker) + marker.length()); - return new ClassPathResource(rest); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - static boolean isSerializable(Class clazz) { - return Serializable.class.isAssignableFrom(clazz); - } - - static void debug(String message, Collection tCollection) { - log.debug(message + System.lineSeparator()); - for (var t : tCollection) - log.debug('\t' + t.toString()); - log.debug(System.lineSeparator()); - } - - static String packageToPath(String packageName) { - var sb = new StringBuilder(); - for (var c : packageName.toCharArray()) - sb.append(c == '.' ? '/' : c); - return sb.toString(); - } - - - static Set getSubTypesOf(Class clzzName, String... packages) { - var set = new HashSet(); - - for (var p : packages) { - var classPathScanningCandidateComponentProvider = new ClassPathScanningCandidateComponentProvider(false); - - classPathScanningCandidateComponentProvider.addIncludeFilter(new AssignableTypeFilter(clzzName)); - - var results = classPathScanningCandidateComponentProvider.findCandidateComponents(p); - for (var r : results) - set.add(r.getBeanClassName()); - } - - return set; - - } -} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisApplicationSpecificBeanFactoryInitializationAotProcessor.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisApplicationSpecificBeanFactoryInitializationAotProcessor.java deleted file mode 100644 index 06748d48147..00000000000 --- a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisApplicationSpecificBeanFactoryInitializationAotProcessor.java +++ /dev/null @@ -1,169 +0,0 @@ -/* Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.flowable.spring.aot; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import java.util.function.Function; - -import org.apache.ibatis.annotations.DeleteProvider; -import org.apache.ibatis.annotations.InsertProvider; -import org.apache.ibatis.annotations.SelectProvider; -import org.apache.ibatis.annotations.UpdateProvider; -import org.springframework.aot.hint.MemberCategory; -import org.springframework.aot.hint.TypeReference; -import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; -import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.boot.autoconfigure.AutoConfigurationPackages; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.ReflectionUtils; - -/** - * Register hints based upon the structure of a particular user's Spring Boot application - * packages and {@link org.springframework.beans.factory.BeanFactory} - * - * @author Josh Long - */ -class MybatisApplicationSpecificBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor { - - private final PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); - - MybatisApplicationSpecificBeanFactoryInitializationAotProcessor() { - } - - private Collection attemptToRegisterXmlResourcesForBasePackage( - ConfigurableListableBeanFactory beanFactory) throws Exception { - var set = new HashSet(); - for (var packageName : AutoConfigurationPackages.get(beanFactory)) { - Assert.hasText(packageName, "the package name must not be empty!"); - var path = FlowableSpringAotUtils.packageToPath(packageName); - for (var resolvedXmlResource : this.resourcePatternResolver - .getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + path + "/**/*.xml")) { - var fqn = resolvedXmlResource.getURI().toString(); - if (resolvedXmlResource.exists()) { - var np = fqn.substring(fqn.indexOf(path)); - var npr = new ClassPathResource(np); - set.add(npr); - } - } - } - return set; - } - - @Override - public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { - - if (!ClassUtils.isPresent("org.mybatis.spring.mapper.MapperFactoryBean", beanFactory.getBeanClassLoader())) - return null; - - try { - var classesToRegister = new HashSet>(); - var proxiesToRegister = new HashSet>(); - var resourcesToRegister = new HashSet(); - resourcesToRegister.addAll(attemptToRegisterXmlResourcesForBasePackage(beanFactory)); - - // Flowable doesn't use mapper classes -// var beanNames = beanFactory.getBeanNamesForType(MapperFactoryBean.class); -// for (var beanName : beanNames) { -// var beanDefinition = beanFactory.getBeanDefinition(beanName.substring(1)); -// var mapperInterface = beanDefinition.getPropertyValues().getPropertyValue("mapperInterface"); -// if (mapperInterface != null && mapperInterface.getValue() != null) { -// var mapperInterfaceType = (Class) mapperInterface.getValue(); -// if (mapperInterfaceType != null) { -// proxiesToRegister.add(mapperInterfaceType); -// resourcesToRegister -// .add(new ClassPathResource(mapperInterfaceType.getName().replace('.', '/').concat(".xml"))); -// registerReflectionTypeIfNecessary(mapperInterfaceType, classesToRegister); -// registerMapperRelationships(mapperInterfaceType, classesToRegister); -// } -// } -// } - - return (generationContext, beanFactoryInitializationCode) -> { - var mcs = MemberCategory.values(); - var runtimeHints = generationContext.getRuntimeHints(); - FlowableSpringAotUtils.debug("proxies", proxiesToRegister); - FlowableSpringAotUtils.debug("classes for reflection", classesToRegister); - FlowableSpringAotUtils.debug("resources", resourcesToRegister); - for (var c : proxiesToRegister) { - runtimeHints.proxies().registerJdkProxy(c); - runtimeHints.reflection().registerType(c, mcs); - } - for (var c : classesToRegister) { - runtimeHints.reflection().registerType(c, mcs); - if (FlowableSpringAotUtils.isSerializable(c)) - runtimeHints.serialization().registerType(TypeReference.of(c.getName())); - } - for (var r : resourcesToRegister) { - if (r.exists()) { - runtimeHints.resources().registerResource(r); - } - } - }; - } // - catch (Exception e) { - throw new RuntimeException(e); - } - } - - @SafeVarargs - private void registerSqlProviderTypes(Method method, Set> registry, - Class annotationType, Function>... providerTypeResolvers) { - for (T annotation : method.getAnnotationsByType(annotationType)) { - for (Function> providerTypeResolver : providerTypeResolvers) { - registerReflectionTypeIfNecessary(providerTypeResolver.apply(annotation), registry); - } - } - } - - private void registerReflectionTypeIfNecessary(Class type, Set> registry) { - if (!type.isPrimitive() && !type.getName().startsWith("java")) { - registry.add(type); - } - } - - private void registerMapperRelationships(Class mapperInterfaceType, Set> registry) { - var methods = ReflectionUtils.getAllDeclaredMethods(mapperInterfaceType); - for (var method : methods) { - if (method.getDeclaringClass() != Object.class) { - - ReflectionUtils.makeAccessible(method); - - registerSqlProviderTypes(method, registry, SelectProvider.class, SelectProvider::value, - SelectProvider::type); - registerSqlProviderTypes(method, registry, InsertProvider.class, InsertProvider::value, - InsertProvider::type); - registerSqlProviderTypes(method, registry, UpdateProvider.class, UpdateProvider::value, - UpdateProvider::type); - registerSqlProviderTypes(method, registry, DeleteProvider.class, DeleteProvider::value, - DeleteProvider::type); - - var returnType = MybatisMapperTypeUtils.resolveReturnClass(mapperInterfaceType, method); - registerReflectionTypeIfNecessary(returnType, registry); - - MybatisMapperTypeUtils.resolveParameterClasses(mapperInterfaceType, method) - .forEach(x -> registerReflectionTypeIfNecessary(x, registry)); - } - } - } - -} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisGlobalBeanFactoryInitializationAotProcessor.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisGlobalBeanFactoryInitializationAotProcessor.java deleted file mode 100644 index af8d9ea4a2f..00000000000 --- a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisGlobalBeanFactoryInitializationAotProcessor.java +++ /dev/null @@ -1,262 +0,0 @@ -/* Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.flowable.spring.aot; - -import java.io.IOException; -import java.io.Serializable; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.WildcardType; -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.RandomAccess; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.stream.Stream; - -import org.apache.ibatis.annotations.CacheNamespace; -import org.apache.ibatis.annotations.Delete; -import org.apache.ibatis.annotations.DeleteProvider; -import org.apache.ibatis.annotations.Flush; -import org.apache.ibatis.annotations.Insert; -import org.apache.ibatis.annotations.InsertProvider; -import org.apache.ibatis.annotations.Many; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.One; -import org.apache.ibatis.annotations.Options; -import org.apache.ibatis.annotations.Property; -import org.apache.ibatis.annotations.Result; -import org.apache.ibatis.annotations.Results; -import org.apache.ibatis.annotations.Select; -import org.apache.ibatis.annotations.SelectProvider; -import org.apache.ibatis.annotations.Update; -import org.apache.ibatis.annotations.UpdateProvider; -import org.apache.ibatis.builder.CacheRefResolver; -import org.apache.ibatis.builder.ResultMapResolver; -import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder; -import org.apache.ibatis.builder.annotation.MethodResolver; -import org.apache.ibatis.builder.annotation.ProviderContext; -import org.apache.ibatis.builder.annotation.ProviderMethodResolver; -import org.apache.ibatis.cache.Cache; -import org.apache.ibatis.cache.CacheKey; -import org.apache.ibatis.cache.NullCacheKey; -import org.apache.ibatis.cache.decorators.BlockingCache; -import org.apache.ibatis.cache.decorators.FifoCache; -import org.apache.ibatis.cache.decorators.LoggingCache; -import org.apache.ibatis.cache.decorators.LruCache; -import org.apache.ibatis.cache.decorators.SerializedCache; -import org.apache.ibatis.cache.decorators.SynchronizedCache; -import org.apache.ibatis.cache.decorators.TransactionalCache; -import org.apache.ibatis.cache.decorators.WeakCache; -import org.apache.ibatis.cache.impl.PerpetualCache; -import org.apache.ibatis.cursor.Cursor; -import org.apache.ibatis.javassist.util.proxy.ProxyFactory; -import org.apache.ibatis.javassist.util.proxy.RuntimeSupport; -import org.apache.ibatis.logging.Log; -import org.apache.ibatis.logging.LogFactory; -import org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl; -import org.apache.ibatis.logging.jdbc.BaseJdbcLogger; -import org.apache.ibatis.logging.jdbc.ConnectionLogger; -import org.apache.ibatis.logging.jdbc.PreparedStatementLogger; -import org.apache.ibatis.logging.jdbc.ResultSetLogger; -import org.apache.ibatis.logging.jdbc.StatementLogger; -import org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl; -import org.apache.ibatis.logging.log4j.Log4jImpl; -import org.apache.ibatis.logging.log4j2.Log4j2AbstractLoggerImpl; -import org.apache.ibatis.logging.log4j2.Log4j2Impl; -import org.apache.ibatis.logging.log4j2.Log4j2LoggerImpl; -import org.apache.ibatis.logging.nologging.NoLoggingImpl; -import org.apache.ibatis.logging.slf4j.Slf4jImpl; -import org.apache.ibatis.logging.stdout.StdOutImpl; -import org.apache.ibatis.mapping.ResultFlag; -import org.apache.ibatis.parsing.XNode; -import org.apache.ibatis.scripting.defaults.RawLanguageDriver; -import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver; -import org.apache.ibatis.session.Configuration; -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.logging.slf4j.SLF4JLogger; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.aot.hint.MemberCategory; -import org.springframework.aot.hint.RuntimeHints; -import org.springframework.aot.hint.TypeReference; -import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; -import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; - -/** - * Register invariant hints for Mybatis that are presumed the same for all applications - * - * @author Josh Long - */ -class MybatisGlobalBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor { - - private final PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); - - private final Logger log = LoggerFactory.getLogger(getClass()); - - MybatisGlobalBeanFactoryInitializationAotProcessor() { - } - - private void registerProxies(RuntimeHints hints) { - var proxies = Set.of(Set.of(Connection.class.getName()), Set.of(SqlSession.class.getName()), - Set.of(PreparedStatement.class.getName(), CallableStatement.class.getName()), - Set.of(ParameterizedType.class.getName(), - "org.springframework.core.SerializableTypeWrapper$SerializableTypeProxy", - Serializable.class.getName()), - Set.of(TypeVariable.class.getName(), - "org.springframework.core.SerializableTypeWrapper$SerializableTypeProxy", - Serializable.class.getName()), - Set.of(WildcardType.class.getName(), - "org.springframework.core.SerializableTypeWrapper$SerializableTypeProxy", - Serializable.class.getName())); - FlowableSpringAotUtils.debug("global proxies", proxies); - for (var p : proxies) { - var parts = p.stream().map(TypeReference::of).toArray(TypeReference[]::new); - hints.proxies().registerJdkProxy(parts); - } - } - - private static Resource newResourceFor(Resource in) { - try { - var marker = "jar!"; - var p = in.getURL().toExternalForm(); - var rest = p.substring(p.lastIndexOf(marker) + marker.length()); - return new ClassPathResource(rest); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - private void registerResources(RuntimeHints hints) throws IOException { - - var resources = new HashSet(); - var config = Stream - .of("org/apache/ibatis/builder/xml/*.dtd", "org/apache/ibatis/builder/xml/*.xsd", - "org/mybatis/spring/config/*.xsd") - .map(p -> ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + p) - .flatMap(p -> { - try { - return Stream.of(this.resourcePatternResolver.getResources(p)); - } - catch (IOException e) { - throw new RuntimeException(e); - } - }) - .map(MybatisGlobalBeanFactoryInitializationAotProcessor::newResourceFor) - .filter(Resource::exists) - .toList(); - - resources.addAll(config); - - FlowableSpringAotUtils.debug("resources", resources); - for (var r : resources) - hints.resources().registerResource(r); - } - - private void registerGlobalTypeHints(RuntimeHints hints) { - - var caches = Set.of(Cache.class, LruCache.class, BlockingCache.class, SerializedCache.class, FifoCache.class, - NullCacheKey.class, PerpetualCache.class, CacheKey.class, WeakCache.class, TransactionalCache.class, - SynchronizedCache.class, LoggingCache.class); - - var collections = Set.of(AbstractList.class, List.class, RandomAccess.class, Cloneable.class, Collection.class, - TreeSet.class, SortedSet.class, Iterator.class, ArrayList.class, HashSet.class, Set.class, Map.class); - - var loggers = Set.of(Log4jImpl.class, Log4j2Impl.class, Log4j2LoggerImpl.class, Log4j2AbstractLoggerImpl.class, - NoLoggingImpl.class, SLF4JLogger.class, StdOutImpl.class, BaseJdbcLogger.class, ConnectionLogger.class, - PreparedStatementLogger.class, ResultSetLogger.class, StatementLogger.class, Jdk14LoggingImpl.class, - JakartaCommonsLoggingImpl.class, Slf4jImpl.class); - - var annotations = Set.of(Select.class, Update.class, Insert.class, Delete.class, SelectProvider.class, - UpdateProvider.class, InsertProvider.class, CacheNamespace.class, Flush.class, DeleteProvider.class, - Options.class, Options.FlushCachePolicy.class, Many.class, Mapper.class, One.class, Property.class, - Result.class, Results.class); - - var memberCategories = MemberCategory.values(); - - var classesForReflection = new HashSet>(); - - classesForReflection.addAll(caches); - classesForReflection.addAll(annotations); - classesForReflection.addAll(loggers); - classesForReflection.addAll(collections); - - // Original version: -// classesForReflection.addAll(Set.of(Serializable.class, SpringBootVFS.class, PerpetualCache.class, Cursor.class, -// Optional.class, LruCache.class, MethodHandles.class, Date.class, HashMap.class, CacheRefResolver.class, -// XNode.class, ResultFlag.class, ResultMapResolver.class, MapperScannerConfigurer.class, -// MethodResolver.class, ProviderMethodResolver.class, ProviderContext.class, -// MapperAnnotationBuilder.class, Logger.class, LogFactory.class, RuntimeSupport.class, Log.class, -// SqlSessionTemplate.class, SqlSessionFactory.class, SqlSessionFactoryBean.class, ProxyFactory.class, -// XMLLanguageDriver.class, RawLanguageDriver.class, Configuration.class, String.class, int.class, -// Number.class, Integer.class, long.class, Long.class, short.class, Short.class, byte.class, Byte.class, -// float.class, Float.class, boolean.class, Boolean.class, double.class, Double.class)); - - classesForReflection.addAll(Set.of(Serializable.class, PerpetualCache.class, Cursor.class, - Optional.class, LruCache.class, MethodHandles.class, Date.class, HashMap.class, CacheRefResolver.class, - XNode.class, ResultFlag.class, ResultMapResolver.class, - MethodResolver.class, ProviderMethodResolver.class, ProviderContext.class, - MapperAnnotationBuilder.class, Logger.class, LogFactory.class, RuntimeSupport.class, Log.class, - SqlSessionFactory.class, ProxyFactory.class, - XMLLanguageDriver.class, RawLanguageDriver.class, Configuration.class, String.class, int.class, - Number.class, Integer.class, long.class, Long.class, short.class, Short.class, byte.class, Byte.class, - float.class, Float.class, boolean.class, Boolean.class, double.class, Double.class)); - - FlowableSpringAotUtils.debug("global types for reflection", classesForReflection); - - for (var c : classesForReflection) { - hints.reflection().registerType(c, memberCategories); - if (FlowableSpringAotUtils.isSerializable(c)) { - hints.serialization().registerType(TypeReference.of(c.getName())); - if (log.isDebugEnabled()) - log.debug("the type " + c.getName() + " is serializable"); - } - } - } - - @Override - public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { - return (generationContext, beanFactoryInitializationCode) -> { - try { - var hints = generationContext.getRuntimeHints(); - registerResources(hints); - registerGlobalTypeHints(hints); - registerProxies(hints); - } // - catch (Throwable throwable) { - throw new RuntimeException(throwable); - } - }; - } - -} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisMapperTypeUtils.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisMapperTypeUtils.java deleted file mode 100644 index 89d6e7dec95..00000000000 --- a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisMapperTypeUtils.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.flowable.spring.aot; - -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.apache.ibatis.reflection.TypeParameterResolver; - -/** - * @author Josh Long - */ -final class MybatisMapperTypeUtils { - - - static Class resolveReturnClass(Class mapperInterface, Method method) { - var resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface); - return typeToClass(resolvedReturnType, method.getReturnType()); - } - - static Set> resolveParameterClasses(Class mapperInterface, Method method) { - return Stream.of(TypeParameterResolver.resolveParamTypes(method, mapperInterface)) - .map(x -> typeToClass(x, x instanceof Class ? (Class) x : Object.class)) - .collect(Collectors.toSet()); - } - - private static Class typeToClass(Type src, Class fallback) { - var result = (Class) null; - if (src instanceof Class c) { - result = c.isArray() ? c.getComponentType() : c; - } - else if (src instanceof ParameterizedType parameterizedType) { - var index = (parameterizedType.getRawType() instanceof Class - && Map.class.isAssignableFrom((Class) parameterizedType.getRawType()) - && parameterizedType.getActualTypeArguments().length > 1) ? 1 : 0; - var actualType = parameterizedType.getActualTypeArguments()[index]; - result = typeToClass(actualType, fallback); - } - if (result == null) { - result = fallback; - } - return result; - } - -} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisMappersBeanFactoryInitializationAotProcessor.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisMappersBeanFactoryInitializationAotProcessor.java deleted file mode 100644 index eb626b8ae57..00000000000 --- a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/aot/MybatisMappersBeanFactoryInitializationAotProcessor.java +++ /dev/null @@ -1,133 +0,0 @@ -/* Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.flowable.spring.aot; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.StringReader; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.xml.parsers.DocumentBuilderFactory; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; -import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.boot.autoconfigure.AutoConfigurationPackages; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.util.FileCopyUtils; -import org.w3c.dom.Element; -import org.xml.sax.InputSource; - -/** - * Discovers any {@literal mappings.xml} and reads them in to then register the - * referenced {@literal .xml} files as resource hints. - * - * @author Josh Long - */ -class MybatisMappersBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor { - - private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); - - MybatisMappersBeanFactoryInitializationAotProcessor() { - } - - private Set persistenceResources(String rootPackage) throws Exception { - var folderFromPackage = FlowableSpringAotUtils.packageToPath(rootPackage); - var patterns = Stream// - .of(folderFromPackage + "/**/mappings.xml")// - .map(path -> ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + path)// - .flatMap(p -> { - try { - return Stream.of(this.resolver.getResources(p)); - } // - catch (IOException e) { - throw new RuntimeException(e); - } - })// - .map(FlowableSpringAotUtils::newResourceFor) - .toList(); - - var resources = new HashSet(); - for (var p : patterns) { - var mappers = mappers(p); - resources.add(p); - resources.addAll(mappers); - } - return resources.stream().filter(Resource::exists).collect(Collectors.toSet()); - } - - protected List getPackagesToScan (BeanFactory b){ - return AutoConfigurationPackages.get(b) ; - } - - @Override - public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { - try { - var packages = getPackagesToScan(beanFactory); - var resources = new HashSet(); - for (var pkg : packages) { - resources.addAll(persistenceResources(pkg)); - } - return (generationContext, beanFactoryInitializationCode) -> { - for (var r : resources) - if (r.exists()) - generationContext.getRuntimeHints().resources().registerResource(r); - }; - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - - private Set mappers(Resource mapping) throws Exception { - var resources = new HashSet(); - try (var in = new InputStreamReader(mapping.getInputStream())) { - var xml = FileCopyUtils.copyToString(in); - resources.addAll(mapperResources(xml)); - } - resources.add(mapping); - return resources; - - } - - private Set mapperResources(String xml) { - try { - var set = new HashSet(); - var dbf = DocumentBuilderFactory.newInstance(); - var db = dbf.newDocumentBuilder(); - var is = new InputSource(new StringReader(xml)); - var doc = db.parse(is); - var mappersElement = (Element) doc.getElementsByTagName("mappers").item(0); - var mapperList = mappersElement.getElementsByTagName("mapper"); - for (var i = 0; i < mapperList.getLength(); i++) { - var mapperElement = (Element) mapperList.item(i); - var resourceValue = mapperElement.getAttribute("resource"); - set.add(new ClassPathResource(resourceValue)); - } - return set; - } // - catch (Throwable throwable) { - throw new RuntimeException(throwable); - } - - } - -} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/BaseAutoDeployResourceContribution.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/BaseAutoDeployResourceContribution.java new file mode 100644 index 00000000000..b67b5a620d3 --- /dev/null +++ b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/BaseAutoDeployResourceContribution.java @@ -0,0 +1,100 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.spring.boot.aot; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Collection; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.aot.generate.GenerationContext; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; +import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; + +/** + * @author Josh Long + * @author Joram Barrez + * @author Filip Hrisafov + */ +public class BaseAutoDeployResourceContribution implements BeanFactoryInitializationAotContribution { + + protected final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + protected final Logger logger = LoggerFactory.getLogger(getClass()); + protected final String locationPrefix; + protected final Collection locationSuffixes; + + public BaseAutoDeployResourceContribution(String locationPrefix, Collection locationSuffixes) { + this.locationPrefix = locationPrefix; + this.locationSuffixes = locationSuffixes; + } + + @Override + public void applyTo(GenerationContext generationContext, BeanFactoryInitializationCode beanFactoryInitializationCode) { + RuntimeHints runtimeHints = generationContext.getRuntimeHints(); + for (String locationSuffix : locationSuffixes) { + String path = locationPrefix + locationSuffix; + try { + for (Resource resource : resolver.getResources(path)) { + ClassPathResource classPathResource = asClasspathResource(resource); + if (classPathResource != null && classPathResource.exists()) { + logger.debug("Registering hints for {}", classPathResource); + applyToResource(classPathResource, runtimeHints); + } + } + } catch (IOException e) { + throw new UncheckedIOException("Failed to find resources for " + path, e); + } + + } + } + + protected void applyToResource(ClassPathResource resource, RuntimeHints hints) { + hints.resources().registerResource(resource); + } + + protected ClassPathResource asClasspathResource(Resource resource) { + if (resource instanceof ClassPathResource) { + return (ClassPathResource) resource; + } + try { + logger.debug("Transforming {} to a classpath resource", resource); + String marker = "jar!"; + String externalFormOfUrl = resource.getURL().toExternalForm(); + if (externalFormOfUrl.contains(marker)) { + String rest = externalFormOfUrl.substring(externalFormOfUrl.lastIndexOf(marker) + marker.length()); + return new ClassPathResource(rest); + } else { + // ugh i think this only works for maven? what about gradle? + var classesSubstring = "classes/"; + var locationOfClassesInUrl = externalFormOfUrl.indexOf(classesSubstring); + if (locationOfClassesInUrl != -1) { + return new ClassPathResource(externalFormOfUrl.substring(locationOfClassesInUrl + classesSubstring.length())); + } + + } + + logger.error("Could not resolve {} as a classpath resource", resource); + return null; + + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/cmmn/FlowableCmmnAutoDeployBeanFactoryInitializationAotProcessor.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/cmmn/FlowableCmmnAutoDeployBeanFactoryInitializationAotProcessor.java new file mode 100644 index 00000000000..10a29cd0695 --- /dev/null +++ b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/cmmn/FlowableCmmnAutoDeployBeanFactoryInitializationAotProcessor.java @@ -0,0 +1,122 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.spring.boot.aot.cmmn; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Collection; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.flowable.cmmn.converter.CmmnXmlConverter; +import org.flowable.cmmn.model.CmmnModel; +import org.flowable.cmmn.model.ImplementationType; +import org.flowable.cmmn.model.ServiceTask; +import org.flowable.spring.boot.aot.BaseAutoDeployResourceContribution; +import org.flowable.spring.boot.cmmn.FlowableCmmnProperties; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.TypeReference; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.util.ClassUtils; +import org.springframework.util.ResourceUtils; + +/** + * @author Josh Long + * @author Joram Barrez + * @author Filip Hrisafov + */ +public class FlowableCmmnAutoDeployBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor { + + protected final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + + @Override + public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { + if (!ClassUtils.isPresent("org.flowable.cmmn.spring.SpringCmmnEngineConfiguration", beanFactory.getBeanClassLoader())) { + return null; + } + + if (!beanFactory.containsBean("cmmnEngineConfiguration")) { + return null; + } + + FlowableCmmnProperties properties = beanFactory.getBeanProvider(FlowableCmmnProperties.class) + .getIfAvailable(); + if (properties == null || !properties.isDeployResources()) { + return null; + } + List locationSuffixes = properties.getResourceSuffixes(); + if (locationSuffixes.isEmpty()) { + return null; + } + String locationPrefix = properties.getResourceLocation(); + if (locationPrefix.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) || locationPrefix.startsWith(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) { + return new CmmnAutoDeployResourceContribution(locationPrefix, locationSuffixes, beanFactory); + } + + return null; + } + + static class CmmnAutoDeployResourceContribution extends BaseAutoDeployResourceContribution { + + protected final ConfigurableListableBeanFactory beanFactory; + + public CmmnAutoDeployResourceContribution(String locationPrefix, Collection locationSuffixes, ConfigurableListableBeanFactory beanFactory) { + super(locationPrefix, locationSuffixes); + this.beanFactory = beanFactory; + } + + @Override + protected void applyToResource(ClassPathResource resource, RuntimeHints hints) { + super.applyToResource(resource, hints); + CmmnXmlConverter cmmXmlConverter = new CmmnXmlConverter(); + CmmnModel cmmnModel = cmmXmlConverter.convertToCmmnModel(() -> { + try { + return resource.getInputStream(); + } catch (IOException e) { + throw new UncheckedIOException("Failed to read resource " + resource, e); + } + }, false, false); + Collection serviceTasks = cmmnModel.getPrimaryCase().findPlanItemDefinitionsOfType(ServiceTask.class); + for (ServiceTask serviceTask : serviceTasks) { + if (ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION.equals(serviceTask.getImplementationType())) { + String expression = serviceTask.getImplementation(); + String expressionWithoutDelimiters = expression.substring(2); + expressionWithoutDelimiters = expressionWithoutDelimiters.substring(0, expressionWithoutDelimiters.length() - 1); + String beanName = expressionWithoutDelimiters; + try { + BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); + String beanClassName = beanDefinition.getBeanClassName(); + if (StringUtils.isNotEmpty(beanClassName)) { + hints.reflection().registerType(TypeReference.of(beanClassName), MemberCategory.values()); + logger.debug("Registering hint for bean name [{}] for service task {} in {}", beanName, serviceTask.getId(), resource); + } else { + logger.debug("No bean class name for bean name [{}] for service task {} in {}", beanName, serviceTask.getId(), resource); + } + + } catch (Throwable throwable) { + logger.error("Couldn't find bean named [{}] for service task {} in {}", beanName, serviceTask.getId(), resource); + } + + } + } + + } + } +} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/dmn/FlowableDmnAutoDeployBeanFactoryInitializationAotProcessor.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/dmn/FlowableDmnAutoDeployBeanFactoryInitializationAotProcessor.java new file mode 100644 index 00000000000..b7c4744d527 --- /dev/null +++ b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/dmn/FlowableDmnAutoDeployBeanFactoryInitializationAotProcessor.java @@ -0,0 +1,63 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.spring.boot.aot.dmn; + +import java.util.List; + +import org.flowable.spring.boot.aot.BaseAutoDeployResourceContribution; +import org.flowable.spring.boot.dmn.FlowableDmnProperties; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.util.ClassUtils; +import org.springframework.util.ResourceUtils; + +/** + * @author Josh Long + * @author Joram Barrez + * @author Filip Hrisafov + */ +public class FlowableDmnAutoDeployBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor { + + protected final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + + @Override + public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { + if (!ClassUtils.isPresent("org.flowable.dmn.spring.SpringDmnEngineConfiguration", beanFactory.getBeanClassLoader())) { + return null; + } + + if (!beanFactory.containsBean("dmnEngineConfiguration")) { + return null; + } + + FlowableDmnProperties properties = beanFactory.getBeanProvider(FlowableDmnProperties.class) + .getIfAvailable(); + if (properties == null || !properties.isDeployResources()) { + return null; + } + List locationSuffixes = properties.getResourceSuffixes(); + if (locationSuffixes.isEmpty()) { + return null; + } + String locationPrefix = properties.getResourceLocation(); + if (locationPrefix.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) || locationPrefix.startsWith(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) { + return new BaseAutoDeployResourceContribution(locationPrefix, locationSuffixes); + } + + return null; + } + +} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/process/FlowableProcessAutoDeployBeanFactoryInitializationAotProcessor.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/process/FlowableProcessAutoDeployBeanFactoryInitializationAotProcessor.java new file mode 100644 index 00000000000..647368db3b5 --- /dev/null +++ b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/aot/process/FlowableProcessAutoDeployBeanFactoryInitializationAotProcessor.java @@ -0,0 +1,122 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.spring.boot.aot.process; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Collection; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.ImplementationType; +import org.flowable.bpmn.model.ServiceTask; +import org.flowable.spring.boot.FlowableProperties; +import org.flowable.spring.boot.aot.BaseAutoDeployResourceContribution; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.TypeReference; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.util.ClassUtils; +import org.springframework.util.ResourceUtils; + +/** + * @author Josh Long + * @author Joram Barrez + * @author Filip Hrisafov + */ +public class FlowableProcessAutoDeployBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor { + + protected final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + + @Override + public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { + if (!ClassUtils.isPresent("org.flowable.spring.SpringProcessEngineConfiguration", beanFactory.getBeanClassLoader())) { + return null; + } + + if (!beanFactory.containsBean("springProcessEngineConfiguration")) { + return null; + } + + FlowableProperties properties = beanFactory.getBeanProvider(FlowableProperties.class) + .getIfAvailable(); + if (properties == null || !properties.isCheckProcessDefinitions()) { + return null; + } + List locationSuffixes = properties.getProcessDefinitionLocationSuffixes(); + if (locationSuffixes.isEmpty()) { + return null; + } + String locationPrefix = properties.getProcessDefinitionLocationPrefix(); + if (locationPrefix.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) || locationPrefix.startsWith(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) { + return new ProcessAutoDeployResourceContribution(locationPrefix, locationSuffixes, beanFactory); + } + + return null; + } + + static class ProcessAutoDeployResourceContribution extends BaseAutoDeployResourceContribution { + + protected final ConfigurableListableBeanFactory beanFactory; + + public ProcessAutoDeployResourceContribution(String locationPrefix, Collection locationSuffixes, ConfigurableListableBeanFactory beanFactory) { + super(locationPrefix, locationSuffixes); + this.beanFactory = beanFactory; + } + + @Override + protected void applyToResource(ClassPathResource resource, RuntimeHints hints) { + super.applyToResource(resource, hints); + BpmnXMLConverter xmlConverter = new BpmnXMLConverter(); + BpmnModel bpmnModel = xmlConverter.convertToBpmnModel(() -> { + try { + return resource.getInputStream(); + } catch (IOException e) { + throw new UncheckedIOException("Failed to read resource " + resource, e); + } + }, false, false); + Collection serviceTasks = bpmnModel.getMainProcess().findFlowElementsOfType(ServiceTask.class); + for (ServiceTask serviceTask : serviceTasks) { + if (ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION.equals(serviceTask.getImplementationType())) { + String expression = serviceTask.getImplementation(); + String expressionWithoutDelimiters = expression.substring(2); + expressionWithoutDelimiters = expressionWithoutDelimiters.substring(0, expressionWithoutDelimiters.length() - 1); + String beanName = expressionWithoutDelimiters; + try { + BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); + String beanClassName = beanDefinition.getBeanClassName(); + if (StringUtils.isNotEmpty(beanClassName)) { + hints.reflection().registerType(TypeReference.of(beanClassName), MemberCategory.values()); + logger.debug("Registering hint for bean name [{}] for service task {} in {}", beanName, serviceTask.getId(), resource); + } else { + logger.debug("No bean class name for bean name [{}] for service task {} in {}", beanName, serviceTask.getId(), resource); + } + + } catch (Throwable throwable) { + logger.error("Couldn't find bean named [{}] for service task {} in {}", beanName, serviceTask.getId(), resource); + } + + } + } + + } + } +} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/environment/FlowableDefaultPropertiesLocationRuntimeHints.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/environment/FlowableDefaultPropertiesLocationRuntimeHints.java new file mode 100644 index 00000000000..17738ffdd48 --- /dev/null +++ b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/environment/FlowableDefaultPropertiesLocationRuntimeHints.java @@ -0,0 +1,65 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.spring.boot.environment; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.support.FilePatternResourceHintsRegistrar; +import org.springframework.boot.env.PropertySourceLoader; +import org.springframework.core.io.support.SpringFactoriesLoader; + +/** + * @author Filip Hrisafov + */ +public class FlowableDefaultPropertiesLocationRuntimeHints implements RuntimeHintsRegistrar { + // This is similar to what is being done in ConfigDataLocationRuntimeHints + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + // This will register all the flowable-default configuration properties + FilePatternResourceHintsRegistrar.forClassPathLocations("/") + .withFileExtensions(getExtensions(classLoader)) + .withFilePrefixes("flowable-default") + .registerHints(hints.resources(), classLoader); + + } + + // The logic below is the same as for the ConfigDataLocationRuntimeHints + /** + * Get the application file extensions to consider. A valid extension starts with a + * dot. + * @param classLoader the classloader to use + * @return the configuration file extensions + */ + protected List getExtensions(ClassLoader classLoader) { + List extensions = new ArrayList<>(); + List propertySourceLoaders = getSpringFactoriesLoader(classLoader) + .load(PropertySourceLoader.class); + for (PropertySourceLoader propertySourceLoader : propertySourceLoaders) { + for (String fileExtension : propertySourceLoader.getFileExtensions()) { + String candidate = "." + fileExtension; + if (!extensions.contains(candidate)) { + extensions.add(candidate); + } + } + } + return extensions; + } + + protected SpringFactoriesLoader getSpringFactoriesLoader(ClassLoader classLoader) { + return SpringFactoriesLoader.forDefaultResourceLocation(classLoader); + } +} diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories index 6fbe8ed6816..94e8b6c6e34 100644 --- a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories +++ b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories @@ -1,5 +1,7 @@ org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\ -org.flowable.spring.aot.FlowableBeanFactoryInitializationAotProcessor,\ -org.flowable.spring.aot.FlowableMybatisMappersBeanFactoryInitializationAotProcessor,\ -org.flowable.spring.aot.MybatisGlobalBeanFactoryInitializationAotProcessor,\ -org.flowable.spring.aot.MybatisApplicationSpecificBeanFactoryInitializationAotProcessor \ No newline at end of file +org.flowable.spring.boot.aot.cmmn.FlowableCmmnAutoDeployBeanFactoryInitializationAotProcessor,\ +org.flowable.spring.boot.aot.dmn.FlowableDmnAutoDeployBeanFactoryInitializationAotProcessor,\ +org.flowable.spring.boot.aot.process.FlowableProcessAutoDeployBeanFactoryInitializationAotProcessor + +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.spring.boot.environment.FlowableDefaultPropertiesLocationRuntimeHints diff --git a/modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/aot/FlowableTaskServiceRuntimeHints.java b/modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/aot/FlowableTaskServiceRuntimeHints.java new file mode 100644 index 00000000000..d69afabbe49 --- /dev/null +++ b/modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/aot/FlowableTaskServiceRuntimeHints.java @@ -0,0 +1,30 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.task.service.impl.aot; + +import org.flowable.common.engine.impl.aot.FlowableSqlResourceHintsRegistrar; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableTaskServiceRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + FlowableSqlResourceHintsRegistrar.registerSqlResources("org/flowable/task/service/db", resourceHints); + } +} diff --git a/modules/flowable-task-service/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-task-service/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..67fb77a12ab --- /dev/null +++ b/modules/flowable-task-service/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.task.service.impl.aot.FlowableTaskServiceRuntimeHints diff --git a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/aot/FlowableVariableServiceRuntimeHints.java b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/aot/FlowableVariableServiceRuntimeHints.java new file mode 100644 index 00000000000..da85a787439 --- /dev/null +++ b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/aot/FlowableVariableServiceRuntimeHints.java @@ -0,0 +1,34 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.variable.service.impl.aot; + +import org.flowable.common.engine.impl.aot.FlowableSqlResourceHintsRegistrar; +import org.flowable.variable.service.impl.db.IbatisVariableTypeHandler; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.ResourceHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; + +/** + * @author Filip Hrisafov + */ +public class FlowableVariableServiceRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + ResourceHints resourceHints = hints.resources(); + FlowableSqlResourceHintsRegistrar.registerSqlResources("org/flowable/variable/service/db", resourceHints); + hints.reflection() + .registerType(IbatisVariableTypeHandler.class, MemberCategory.values()); + } +} diff --git a/modules/flowable-variable-service/src/main/resources/META-INF/spring/aot.factories b/modules/flowable-variable-service/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000000..45df3f88e19 --- /dev/null +++ b/modules/flowable-variable-service/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.flowable.variable.service.impl.aot.FlowableVariableServiceRuntimeHints diff --git a/pom.xml b/pom.xml index 3a76fe2bcb9..d8ee6d15faa 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,7 @@ 2.0.9 4.0.15 3.4.0 + 0.9.27 4.13.2 5.9.3 @@ -710,6 +711,12 @@ + + org.graalvm.buildtools + native-maven-plugin + ${native-build-tools-plugin.version} + true + org.codehaus.mojo exec-maven-plugin