This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch feat/ognl-3.5-upgrade in repository https://gitbox.apache.org/repos/asf/struts.git
commit e2e8fa1f332c11ec4de357561c025cb771d8974e Author: Lukasz Lenart <[email protected]> AuthorDate: Mon Apr 6 18:14:29 2026 +0200 WW-5326 feat(ognl): introduce StrutsContext extending OgnlContext<StrutsContext> Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../org/apache/struts2/ognl/StrutsContext.java | 53 +++++++++++++++++++++ .../org/apache/struts2/ognl/StrutsContextTest.java | 54 ++++++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/core/src/main/java/org/apache/struts2/ognl/StrutsContext.java b/core/src/main/java/org/apache/struts2/ognl/StrutsContext.java new file mode 100644 index 000000000..e2b7b4b93 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/ognl/StrutsContext.java @@ -0,0 +1,53 @@ +/* + * 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.struts2.ognl; + +import ognl.ClassResolver; +import ognl.MemberAccess; +import ognl.OgnlContext; +import ognl.TypeConverter; + +/** + * Struts-specific OGNL evaluation context. Extends {@link OgnlContext} with the + * self-bounded generic parameter to enable type-safe access in all OGNL interface + * implementations ({@link MemberAccess}, {@link ognl.PropertyAccessor}, etc.). + * + * <p>Phase 1: minimal subclass delegating to super constructors. + * Future phases will promote stringly-typed map entries (e.g. {@code DENY_METHOD_EXECUTION}, + * {@code CREATE_NULL_OBJECTS}) to proper typed fields.</p> + * + * @since 7.2.0 + */ +public class StrutsContext extends OgnlContext<StrutsContext> { + + public StrutsContext(MemberAccess<StrutsContext> memberAccess) { + super(memberAccess); + } + + public StrutsContext(MemberAccess<StrutsContext> memberAccess, + ClassResolver<StrutsContext> classResolver) { + super(memberAccess, classResolver); + } + + public StrutsContext(MemberAccess<StrutsContext> memberAccess, + ClassResolver<StrutsContext> classResolver, + TypeConverter<StrutsContext> typeConverter) { + super(memberAccess, classResolver, typeConverter); + } +} diff --git a/core/src/test/java/org/apache/struts2/ognl/StrutsContextTest.java b/core/src/test/java/org/apache/struts2/ognl/StrutsContextTest.java new file mode 100644 index 000000000..be0a07305 --- /dev/null +++ b/core/src/test/java/org/apache/struts2/ognl/StrutsContextTest.java @@ -0,0 +1,54 @@ +package org.apache.struts2.ognl; + +import ognl.ClassResolver; +import ognl.MemberAccess; +import ognl.TypeConverter; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +@SuppressWarnings("unchecked") +class StrutsContextTest { + + @Test + void shouldCreateContextWithRequiredMemberAccess() { + MemberAccess<StrutsContext> memberAccess = mock(MemberAccess.class); + var context = new StrutsContext(memberAccess); + + assertThat(context).isNotNull(); + assertThat(context.getMemberAccess()).isSameAs(memberAccess); + } + + @Test + void shouldCreateContextWithAllComponents() { + MemberAccess<StrutsContext> memberAccess = mock(MemberAccess.class); + ClassResolver<StrutsContext> classResolver = mock(ClassResolver.class); + TypeConverter<StrutsContext> typeConverter = mock(TypeConverter.class); + + var context = new StrutsContext(memberAccess, classResolver, typeConverter); + + assertThat(context.getMemberAccess()).isSameAs(memberAccess); + assertThat(context.getClassResolver()).isSameAs(classResolver); + assertThat(context.getTypeConverter()).isSameAs(typeConverter); + } + + @Test + void shouldSupportRootObject() { + MemberAccess<StrutsContext> memberAccess = mock(MemberAccess.class); + var root = new Object(); + var context = new StrutsContext(memberAccess); + context.withRoot(root); + + assertThat(context.getRoot()).isSameAs(root); + } + + @Test + void shouldImplementMapInterface() { + MemberAccess<StrutsContext> memberAccess = mock(MemberAccess.class); + var context = new StrutsContext(memberAccess); + + context.put("testKey", "testValue"); + assertThat(context.get("testKey")).isEqualTo("testValue"); + } +}
