This is an automated email from the ASF dual-hosted git repository. ahuber pushed a commit to branch 3969-jpa.#safeguard in repository https://gitbox.apache.org/repos/asf/causeway.git
commit 730a93b98f9eeb33232134bed0972f56778448e3 Author: andi-huber <[email protected]> AuthorDate: Wed Feb 18 13:58:18 2026 +0100 CAUSEWAY-3969: adds #safeguard (stubs) Task-Url: https://issues.apache.org/jira/browse/CAUSEWAY-3969 --- .../core/config/CausewayConfiguration.java | 45 +++++++++++++---- .../CausewayModulePersistenceJpaIntegration.java | 4 +- .../integration/services/JpaWeavingSafeguard.java | 59 ++++++++++++++++++++++ .../services/JpaWeavingSafeguardService.java | 54 ++++++++++++++++++++ 4 files changed, 151 insertions(+), 11 deletions(-) diff --git a/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java b/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java index ce719995e52..19ff68a02d3 100644 --- a/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java +++ b/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java @@ -90,6 +90,8 @@ import org.apache.causeway.commons.internal.base._NullSafe; import org.apache.causeway.commons.internal.base._StableValue; import org.apache.causeway.commons.internal.context._Context; +import org.apache.causeway.core.config.CausewayConfiguration.Core; +import org.apache.causeway.core.config.CausewayConfiguration.Viewer; import org.apache.causeway.core.config.metamodel.facets.ActionConfigOptions; import org.apache.causeway.core.config.metamodel.facets.AssociationLayoutConfigOptions; import org.apache.causeway.core.config.metamodel.facets.CollectionLayoutConfigOptions; @@ -1030,7 +1032,7 @@ public CssClass( "approve.*:btn-success", "reject.*:btn-danger", - }) + }) final String[] patterns) { this(patterns, new _StableValue<>()); } @@ -1161,7 +1163,7 @@ public CssClassFa( "wizard.*:fa-solid fa-wand-magic-sparkles" - }) + }) final String[] patterns) { this(patterns, new _StableValue<>()); } @@ -1993,7 +1995,9 @@ public record Persistence( @DefaultValue Commons commons, @DefaultValue - Schema schema) { + Schema schema, + @DefaultValue + Weaving weaving) { public record Commons( @DefaultValue @@ -2084,6 +2088,28 @@ public record Schema( @DefaultValue("CREATE SCHEMA IF NOT EXISTS %S") String createSchemaSqlTemplate) { } + + public record Weaving( + @DefaultValue("REQUIRE_WEAVED_WHEN_ANY_SUB_IS_WEAVED") + SafeguardMode safeguardMode) { + public enum SafeguardMode { + /** + * Safeguard only logs warnings, but otherwise does not prevent an application from launching. + */ + LOG_ONLY, + /** + * (Default) Requires for any entity type hierarchy that when classes are weaved, + * their super classes also need to be weaved. + * + * <p>Prevents entity type hierarchies from failing later at runtime. + */ + REQUIRE_WEAVED_WHEN_ANY_SUB_IS_WEAVED, + /** + * Enforces weaving on all encountered entity type hierarchies. + */ + REQUIRE_WEAVED + } + } } public record Prototyping( @@ -3167,21 +3193,21 @@ public record DevelopmentUtilities( @DefaultValue("false") boolean enable) { } - + public record FileUpload( /** - * If left empty, the default allows ['image', 'html', 'text', 'video', 'audio', 'flash', 'object'], + * If left empty, the default allows ['image', 'html', 'text', 'video', 'audio', 'flash', 'object'], * where 'object' enables fallback behavior. We remove this here. - * + * * @see https://plugins.krajee.com/file-input/plugin-options#disabledPreviewTypes */ @DefaultValue({"object"}) List<String> disabledPreviewTypes, /** * Some mime types can trigger unwanted download behavior, dependent on browser and or OS settings. - * + * * <p>We have seen CSV files causing issues, so we disallow those by default. - * + * * @see https://plugins.krajee.com/file-input/plugin-options#disabledPreviewMimeTypes */ @DefaultValue({"text/csv"}) @@ -4331,9 +4357,8 @@ public void initialize(final AssignableFrom assignableFrom) { public boolean isValid( final Class<?> candidateClass, final ConstraintValidatorContext constraintContext) { - if (superType.get() == null || candidateClass == null) { + if (superType.get() == null || candidateClass == null) return true; - } return superType.get().isAssignableFrom(candidateClass); } } diff --git a/persistence/jpa/integration/src/main/java/org/apache/causeway/persistence/jpa/integration/CausewayModulePersistenceJpaIntegration.java b/persistence/jpa/integration/src/main/java/org/apache/causeway/persistence/jpa/integration/CausewayModulePersistenceJpaIntegration.java index d01144e19e2..34ae16da4db 100644 --- a/persistence/jpa/integration/src/main/java/org/apache/causeway/persistence/jpa/integration/CausewayModulePersistenceJpaIntegration.java +++ b/persistence/jpa/integration/src/main/java/org/apache/causeway/persistence/jpa/integration/CausewayModulePersistenceJpaIntegration.java @@ -34,6 +34,7 @@ import org.apache.causeway.persistence.commons.CausewayModulePersistenceCommons; import org.apache.causeway.persistence.jpa.integration.entity.JpaEntityIntegration; import org.apache.causeway.persistence.jpa.integration.services.JpaSupportServiceUsingSpring; +import org.apache.causeway.persistence.jpa.integration.services.JpaWeavingSafeguardService; import org.apache.causeway.persistence.jpa.integration.typeconverters.applib.CausewayBookmarkConverter; import org.apache.causeway.persistence.jpa.integration.typeconverters.applib.CausewayLocalResourcePathConverter; import org.apache.causeway.persistence.jpa.integration.typeconverters.applib.CausewayMarkupConverter; @@ -63,6 +64,7 @@ // @Service's JpaSupportServiceUsingSpring.class, + JpaWeavingSafeguardService.class, }) @EntityScan(basePackageClasses = { @@ -89,7 +91,7 @@ public class CausewayModulePersistenceJpaIntegration { //TODO close issue https://issues.apache.org/jira/browse/CAUSEWAY-3895 once this can be removed @Bean @Primary - public JpaContext defaultJpaContextWorkaround(Set<EntityManager> entityManagers) { + public JpaContext defaultJpaContextWorkaround(final Set<EntityManager> entityManagers) { var setOfOne = Set.of(entityManagers.iterator().next()); return new DefaultJpaContext(setOfOne); } diff --git a/persistence/jpa/integration/src/main/java/org/apache/causeway/persistence/jpa/integration/services/JpaWeavingSafeguard.java b/persistence/jpa/integration/src/main/java/org/apache/causeway/persistence/jpa/integration/services/JpaWeavingSafeguard.java new file mode 100644 index 00000000000..424d28ec6cb --- /dev/null +++ b/persistence/jpa/integration/src/main/java/org/apache/causeway/persistence/jpa/integration/services/JpaWeavingSafeguard.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.causeway.persistence.jpa.integration.services; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.causeway.commons.internal.reflection._ClassCache; +import org.apache.causeway.commons.internal.reflection._Reflect; +import org.apache.causeway.commons.internal.reflection._Reflect.InterfacePolicy; +import org.apache.causeway.core.config.CausewayConfiguration; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public record JpaWeavingSafeguard( + CausewayConfiguration.Persistence.Weaving.SafeguardMode mode, + _ClassCache classCache) { + + public JpaWeavingSafeguard(final CausewayConfiguration.Persistence.Weaving.SafeguardMode mode) { + this(mode, _ClassCache.getInstance()); + } + + public void checkAll(final Iterable<Class<?>> entityTypes) { + var seen = new HashSet<Class<?>>(); + for(final Class<?> entityType : entityTypes) { + _Reflect.streamTypeHierarchy(entityType, InterfacePolicy.EXCLUDE) + .forEach(type->check(type, seen)); + } + } + + private void check(final Class<?> entityType, final Set<Class<?>> seen) { + if(!seen.add(entityType)) + return; // skip when already checked + + log.info("weaved {}{}", + classCache.isByteCodeEnhanced(entityType) + ? "[#]" + : "[-]", + entityType.getName()); + } + +} diff --git a/persistence/jpa/integration/src/main/java/org/apache/causeway/persistence/jpa/integration/services/JpaWeavingSafeguardService.java b/persistence/jpa/integration/src/main/java/org/apache/causeway/persistence/jpa/integration/services/JpaWeavingSafeguardService.java new file mode 100644 index 00000000000..855ea6bc891 --- /dev/null +++ b/persistence/jpa/integration/src/main/java/org/apache/causeway/persistence/jpa/integration/services/JpaWeavingSafeguardService.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.causeway.persistence.jpa.integration.services; + +import java.util.HashSet; +import java.util.Optional; +import java.util.stream.Collectors; + +import jakarta.inject.Inject; + +import org.springframework.stereotype.Service; + +import org.apache.causeway.applib.events.metamodel.MetamodelListener; +import org.apache.causeway.core.config.CausewayConfiguration; +import org.apache.causeway.core.config.beans.CausewayBeanMetaData.PersistenceStack; +import org.apache.causeway.core.config.beans.CausewayBeanTypeRegistry; + +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +public class JpaWeavingSafeguardService implements MetamodelListener { + + @Inject CausewayConfiguration config; + @Inject CausewayBeanTypeRegistry causewayBeanTypeRegistry; + + @Override public void onMetamodelLoaded() { } + @Override public void onMetamodelAboutToBeLoaded() { + var safeguardMode = Optional.ofNullable(config.persistence().weaving().safeguardMode()) + .orElse(CausewayConfiguration.Persistence.Weaving.SafeguardMode.REQUIRE_WEAVED_WHEN_ANY_SUB_IS_WEAVED); + var jpaWeavingSafeguard = new JpaWeavingSafeguard(safeguardMode); + jpaWeavingSafeguard.checkAll(causewayBeanTypeRegistry + .streamEntityTypes(PersistenceStack.JPA) + .collect(Collectors.toCollection(HashSet::new))); + } + +} +
