This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch feature/WW-5512-optional-inject in repository https://gitbox.apache.org/repos/asf/struts.git
commit a33c162f53f96879f98f43eab8bea45b61ba03c7 Author: Lukasz Lenart <lukaszlen...@apache.org> AuthorDate: Sun Jan 5 17:45:11 2025 +0100 WW-5512 Extends the container to support injecting optional parameters into constructor --- .../opensymphony/xwork2/inject/ContainerImpl.java | 8 ++- .../xwork2/inject/ContainerImplTest.java | 83 ++++++++++++++++------ 2 files changed, 67 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java b/core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java index 455f8a449..1596077ab 100644 --- a/core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java +++ b/core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java @@ -419,8 +419,12 @@ class ContainerImpl implements Container { // First time through... constructionContext.startConstruction(); try { - final Object[] parameters = getParameters(constructor, context, parameterInjectors); - t = constructor.newInstance(parameters); + if (constructor.getParameterCount() > 0 && parameterInjectors == null) { + t = constructor.newInstance(new Object[constructor.getParameterCount()]); + } else { + final Object[] parameters = getParameters(constructor, context, parameterInjectors); + t = constructor.newInstance(parameters); + } constructionContext.setProxyDelegates(t); } finally { constructionContext.finishConstruction(); diff --git a/core/src/test/java/com/opensymphony/xwork2/inject/ContainerImplTest.java b/core/src/test/java/com/opensymphony/xwork2/inject/ContainerImplTest.java index 85ef9ace8..d3e479d19 100644 --- a/core/src/test/java/com/opensymphony/xwork2/inject/ContainerImplTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/inject/ContainerImplTest.java @@ -29,6 +29,7 @@ import java.util.concurrent.Callable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; @@ -49,6 +50,7 @@ public class ContainerImplTest { ContainerBuilder cb = new ContainerBuilder(); cb.constant("methodCheck.name", "Lukasz"); cb.constant("fieldCheck.name", "Lukasz"); + cb.constant("constructorCheck.name", "Lukasz"); cb.factory(EarlyInitializable.class, EarlyInitializableBean.class, Scope.SINGLETON); cb.factory(Initializable.class, InitializableBean.class, Scope.SINGLETON); cb.factory(EarlyInitializable.class, "prototypeEarlyInitializable", EarlyInitializableBean.class, Scope.PROTOTYPE); @@ -65,15 +67,29 @@ public class ContainerImplTest { } @Test - public void fieldInjector() throws Exception { + public void fieldInjector() { FieldCheck fieldCheck = new FieldCheck(); c.inject(fieldCheck); - assertEquals(fieldCheck.getName(), "Lukasz"); + assertEquals("Lukasz", fieldCheck.getName()); } @Test - public void methodInjector() throws Exception { - c.inject(new MethodCheck()); + public void methodInjector() { + MethodCheck methodCheck = new MethodCheck(); + c.inject(methodCheck); + assertEquals("Lukasz", methodCheck.getName()); + } + + @Test + public void constructorInjector() { + ConstructorCheck constructorCheck = c.inject(ConstructorCheck.class); + assertEquals("Lukasz", constructorCheck.getName()); + } + + @Test + public void optionalConstructorInjector() { + OptionalConstructorCheck constructorCheck = c.inject(OptionalConstructorCheck.class); + assertNull(constructorCheck.getName()); } /** @@ -92,7 +108,7 @@ public class ContainerImplTest { * Inject values into method under SecurityManager */ @Test - public void testMethodInjectorWithSecurityEnabled() throws Exception { + public void testMethodInjectorWithSecurityEnabled() { assumeTrue(SystemUtils.isJavaVersionAtMost(JavaVersion.JAVA_20)); System.setSecurityManager(new TestSecurityManager()); assertThrows(DependencyException.class, () -> c.inject(new MethodCheck())); @@ -101,7 +117,7 @@ public class ContainerImplTest { } @Test - public void testEarlyInitializable() throws Exception { + public void testEarlyInitializable() { assertTrue("should being initialized already", EarlyInitializableBean.initializedEarly); EarlyInitializableCheck earlyInitializableCheck = new EarlyInitializableCheck(); @@ -148,22 +164,19 @@ public class ContainerImplTest { final InitializableCheck initializableCheck3 = new InitializableCheck(); final TestScopeStrategy testScopeStrategy = new TestScopeStrategy(); - Thread thread = new Thread(new Runnable() { - @Override - public void run() { - ContainerBuilder cb2 = new ContainerBuilder(); - cb2.factory(EarlyInitializable.class, EarlyInitializableBean.class, Scope.SINGLETON); - cb2.factory(Initializable.class, InitializableBean.class, Scope.SINGLETON); - cb2.factory(EarlyInitializable.class, "prototypeEarlyInitializable", EarlyInitializableBean.class, Scope.PROTOTYPE); - cb2.factory(Initializable.class, "prototypeInitializable", InitializableBean.class, Scope.PROTOTYPE); - cb2.factory(Initializable.class, "requestInitializable", InitializableBean.class, Scope.REQUEST); - cb2.factory(Initializable.class, "sessionInitializable", InitializableBean.class, Scope.SESSION); - cb2.factory(Initializable.class, "threadInitializable", InitializableBean.class, Scope.THREAD); - cb2.factory(Initializable.class, "wizardInitializable", InitializableBean.class, Scope.WIZARD); - Container c2 = cb2.create(false); - c2.setScopeStrategy(testScopeStrategy); - c2.inject(initializableCheck3); - } + Thread thread = new Thread(() -> { + ContainerBuilder cb2 = new ContainerBuilder(); + cb2.factory(EarlyInitializable.class, EarlyInitializableBean.class, Scope.SINGLETON); + cb2.factory(Initializable.class, InitializableBean.class, Scope.SINGLETON); + cb2.factory(EarlyInitializable.class, "prototypeEarlyInitializable", EarlyInitializableBean.class, Scope.PROTOTYPE); + cb2.factory(Initializable.class, "prototypeInitializable", InitializableBean.class, Scope.PROTOTYPE); + cb2.factory(Initializable.class, "requestInitializable", InitializableBean.class, Scope.REQUEST); + cb2.factory(Initializable.class, "sessionInitializable", InitializableBean.class, Scope.SESSION); + cb2.factory(Initializable.class, "threadInitializable", InitializableBean.class, Scope.THREAD); + cb2.factory(Initializable.class, "wizardInitializable", InitializableBean.class, Scope.WIZARD); + Container c2 = cb2.create(false); + c2.setScopeStrategy(testScopeStrategy); + c2.inject(initializableCheck3); }); thread.run(); thread.join(); @@ -205,6 +218,32 @@ public class ContainerImplTest { } + public static class ConstructorCheck { + private String name; + + @Inject("constructorCheck.name") + public ConstructorCheck(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + public static class OptionalConstructorCheck { + private String name; + + @Inject(value = "nonExistingConstant", required = false) + public OptionalConstructorCheck(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + class InitializableCheck { private Initializable initializable;