This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch WW-5641-json-writer-reader-override in repository https://gitbox.apache.org/repos/asf/struts.git
commit 48c30609292c6776a64d811328a66c367fafcb23 Author: Lukasz Lenart <[email protected]> AuthorDate: Mon Jul 6 19:27:36 2026 +0200 WW-5641 fix: resolve JSON writer/reader from constant at runtime Restore deferred by-name resolution in JSONUtil so struts.json.writer and struts.json.reader overrides from an application config are honored again. The 7.2.x <bean-selection> alias is chosen at plugin-parse time, before the app config is folded in, so it locked the default StrutsJSONWriter/Reader. Co-Authored-By: Claude Opus 4.8 <[email protected]> --- .../java/org/apache/struts2/json/JSONUtil.java | 9 +++- .../apache/struts2/json/CustomTestJSONReader.java | 38 ++++++++++++++ .../apache/struts2/json/CustomTestJSONWriter.java | 50 ++++++++++++++++++ .../struts2/json/JSONWriterOverrideTest.java | 60 ++++++++++++++++++++++ .../src/test/resources/struts-json-override.xml | 12 +++++ 5 files changed, 168 insertions(+), 1 deletion(-) diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java index 78bceaacf..541f7a1a9 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java @@ -40,6 +40,7 @@ import java.util.Arrays; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.apache.struts2.inject.Container; import org.apache.struts2.inject.Inject; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; @@ -63,6 +64,13 @@ public class JSONUtil { private JSONWriter writer; @Inject + public void setContainer(Container container) { + setWriter(container.getInstance(JSONWriter.class, + container.getInstance(String.class, JSONConstants.JSON_WRITER))); + setReader(container.getInstance(JSONReader.class, + container.getInstance(String.class, JSONConstants.JSON_READER))); + } + public void setReader(JSONReader reader) { this.reader = reader; } @@ -71,7 +79,6 @@ public class JSONUtil { return reader; } - @Inject public void setWriter(JSONWriter writer) { this.writer = writer; } diff --git a/plugins/json/src/test/java/org/apache/struts2/json/CustomTestJSONReader.java b/plugins/json/src/test/java/org/apache/struts2/json/CustomTestJSONReader.java new file mode 100644 index 000000000..4a5482357 --- /dev/null +++ b/plugins/json/src/test/java/org/apache/struts2/json/CustomTestJSONReader.java @@ -0,0 +1,38 @@ +/* + * 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.json; + +/** + * Marker reader proving that a user-configured {@code struts.json.reader} override + * wins over the default {@link StrutsJSONReader}. + */ +public class CustomTestJSONReader implements JSONReader { + + public static final String SENTINEL = "__customReader__"; + + @Override + public Object read(String string) throws JSONException { + return SENTINEL; + } + + @Override public void setMaxElements(int maxElements) {} + @Override public void setMaxDepth(int maxDepth) {} + @Override public void setMaxStringLength(int maxStringLength) {} + @Override public void setMaxKeyLength(int maxKeyLength) {} +} diff --git a/plugins/json/src/test/java/org/apache/struts2/json/CustomTestJSONWriter.java b/plugins/json/src/test/java/org/apache/struts2/json/CustomTestJSONWriter.java new file mode 100644 index 000000000..9f252ffec --- /dev/null +++ b/plugins/json/src/test/java/org/apache/struts2/json/CustomTestJSONWriter.java @@ -0,0 +1,50 @@ +/* + * 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.json; + +import java.util.Collection; +import java.util.regex.Pattern; + +/** + * Marker writer proving that a user-configured {@code struts.json.writer} override + * wins over the default {@link StrutsJSONWriter}. Emits a sentinel so output-level + * assertions are unambiguous. + */ +public class CustomTestJSONWriter implements JSONWriter { + + public static final String SENTINEL = "{\"__customWriter__\":true}"; + + @Override + public String write(Object object) throws JSONException { + return SENTINEL; + } + + @Override + public String write(Object object, Collection<Pattern> excludeProperties, + Collection<Pattern> includeProperties, + boolean excludeNullProperties) throws JSONException { + return SENTINEL; + } + + @Override public void setIgnoreHierarchy(boolean ignoreHierarchy) {} + @Override public void setEnumAsBean(boolean enumAsBean) {} + @Override public void setDateFormatter(String defaultDateFormat) {} + @Override public void setCacheBeanInfo(boolean cacheBeanInfo) {} + @Override public void setExcludeProxyProperties(boolean excludeProxyProperties) {} +} diff --git a/plugins/json/src/test/java/org/apache/struts2/json/JSONWriterOverrideTest.java b/plugins/json/src/test/java/org/apache/struts2/json/JSONWriterOverrideTest.java new file mode 100644 index 000000000..fd36d68b2 --- /dev/null +++ b/plugins/json/src/test/java/org/apache/struts2/json/JSONWriterOverrideTest.java @@ -0,0 +1,60 @@ +/* + * 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.json; + +import org.apache.struts2.junit.StrutsTestCase; + +import java.util.HashMap; +import java.util.Map; + +/** + * Regression test for WW-5641: {@code struts.json.writer} / {@code struts.json.reader} + * overrides from an application config were ignored on the 7.2.x line. + * + * <p>Boots the real Dispatcher config chain so the provider ordering that causes the bug + * (JSON plugin {@code <bean-selection>} running before the app override) is reproduced.</p> + */ +public class JSONWriterOverrideTest extends StrutsTestCase { + + @Override + protected void setupBeforeInitDispatcher() throws Exception { + Map<String, String> params = new HashMap<>(); + params.put("config", "struts-default.xml,struts-plugin.xml,struts-json-override.xml"); + dispatcherInitParams = params; + } + + /** + * The effective writer used by JSONUtil must be the override, not StrutsJSONWriter. + */ + public void testCustomWriterIsUsedBySerialize() throws Exception { + JSONUtil jsonUtil = container.getInstance(JSONUtil.class); + String output = jsonUtil.serialize(new Object(), false); + assertEquals("struts.json.writer override was ignored; default StrutsJSONWriter was used", + CustomTestJSONWriter.SENTINEL, output); + } + + /** + * The effective reader used by JSONUtil must be the override, not StrutsJSONReader. + */ + public void testCustomReaderIsUsed() { + JSONUtil jsonUtil = container.getInstance(JSONUtil.class); + assertEquals("struts.json.reader override was ignored; default StrutsJSONReader was used", + CustomTestJSONReader.class, jsonUtil.getReader().getClass()); + } +} diff --git a/plugins/json/src/test/resources/struts-json-override.xml b/plugins/json/src/test/resources/struts-json-override.xml new file mode 100644 index 000000000..e1ab475da --- /dev/null +++ b/plugins/json/src/test/resources/struts-json-override.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE struts PUBLIC + "-//Apache Software Foundation//DTD Struts Configuration 6.0//EN" + "https://struts.apache.org/dtds/struts-6.0.dtd"> +<struts> + <bean type="org.apache.struts2.json.JSONWriter" name="customTestWriter" + class="org.apache.struts2.json.CustomTestJSONWriter" scope="prototype"/> + <bean type="org.apache.struts2.json.JSONReader" name="customTestReader" + class="org.apache.struts2.json.CustomTestJSONReader" scope="prototype"/> + <constant name="struts.json.writer" value="customTestWriter"/> + <constant name="struts.json.reader" value="customTestReader"/> +</struts>
