From 4bb837582e7bf4cac4efb0877432652e1fda9297 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sun, 7 Jan 2018 23:19:47 +0100 Subject: [PATCH] Support for static field access on non-public enums Issue: SPR-16284 (cherry picked from commit 9beb978) --- .../beans/TypeConverterDelegate.java | 4 +- .../beans/BeanWrapperEnumTests.java | 62 ++++++++++++++----- .../DefaultListableBeanFactoryTests.java | 32 +++++++++- 3 files changed, 79 insertions(+), 19 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java b/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java index 8ffdc5d8c6..6531d6b9a0 100644 --- a/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java +++ b/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -35,6 +35,7 @@ import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; import org.springframework.util.ClassUtils; import org.springframework.util.NumberUtils; +import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; /** @@ -353,6 +354,7 @@ class TypeConverterDelegate { // to be checked, hence we don't return it right away. try { Field enumField = requiredType.getField(trimmedValue); + ReflectionUtils.makeAccessible(enumField); convertedValue = enumField.get(null); } catch (Throwable ex) { diff --git a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperEnumTests.java b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperEnumTests.java index f97ec8f749..f5c87cdf9d 100644 --- a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperEnumTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperEnumTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -31,11 +31,11 @@ import static org.junit.Assert.*; * @author Juergen Hoeller * @author Chris Beams */ -public final class BeanWrapperEnumTests { +public class BeanWrapperEnumTests { @Test public void testCustomEnum() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("customEnum", "VALUE_1"); assertEquals(CustomEnum.VALUE_1, gb.getCustomEnum()); @@ -43,7 +43,7 @@ public final class BeanWrapperEnumTests { @Test public void testCustomEnumWithNull() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("customEnum", null); assertEquals(null, gb.getCustomEnum()); @@ -51,7 +51,7 @@ public final class BeanWrapperEnumTests { @Test public void testCustomEnumWithEmptyString() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("customEnum", ""); assertEquals(null, gb.getCustomEnum()); @@ -59,7 +59,7 @@ public final class BeanWrapperEnumTests { @Test public void testCustomEnumArrayWithSingleValue() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("customEnumArray", "VALUE_1"); assertEquals(1, gb.getCustomEnumArray().length); @@ -68,7 +68,7 @@ public final class BeanWrapperEnumTests { @Test public void testCustomEnumArrayWithMultipleValues() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("customEnumArray", new String[] {"VALUE_1", "VALUE_2"}); assertEquals(2, gb.getCustomEnumArray().length); @@ -78,7 +78,7 @@ public final class BeanWrapperEnumTests { @Test public void testCustomEnumArrayWithMultipleValuesAsCsv() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("customEnumArray", "VALUE_1,VALUE_2"); assertEquals(2, gb.getCustomEnumArray().length); @@ -88,7 +88,7 @@ public final class BeanWrapperEnumTests { @Test public void testCustomEnumSetWithSingleValue() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("customEnumSet", "VALUE_1"); assertEquals(1, gb.getCustomEnumSet().size()); @@ -97,7 +97,7 @@ public final class BeanWrapperEnumTests { @Test public void testCustomEnumSetWithMultipleValues() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("customEnumSet", new String[] {"VALUE_1", "VALUE_2"}); assertEquals(2, gb.getCustomEnumSet().size()); @@ -107,7 +107,7 @@ public final class BeanWrapperEnumTests { @Test public void testCustomEnumSetWithMultipleValuesAsCsv() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("customEnumSet", "VALUE_1,VALUE_2"); assertEquals(2, gb.getCustomEnumSet().size()); @@ -117,7 +117,7 @@ public final class BeanWrapperEnumTests { @Test public void testCustomEnumSetWithGetterSetterMismatch() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setPropertyValue("customEnumSetMismatch", new String[] {"VALUE_1", "VALUE_2"}); assertEquals(2, gb.getCustomEnumSet().size()); @@ -127,7 +127,7 @@ public final class BeanWrapperEnumTests { @Test public void testStandardEnumSetWithMultipleValues() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setConversionService(new DefaultConversionService()); assertNull(gb.getStandardEnumSet()); @@ -139,7 +139,7 @@ public final class BeanWrapperEnumTests { @Test public void testStandardEnumSetWithAutoGrowing() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setAutoGrowNestedPaths(true); assertNull(gb.getStandardEnumSet()); @@ -149,11 +149,11 @@ public final class BeanWrapperEnumTests { @Test public void testStandardEnumMapWithMultipleValues() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setConversionService(new DefaultConversionService()); assertNull(gb.getStandardEnumMap()); - Map map = new LinkedHashMap(); + Map map = new LinkedHashMap<>(); map.put("VALUE_1", 1); map.put("VALUE_2", 2); bw.setPropertyValue("standardEnumMap", map); @@ -164,7 +164,7 @@ public final class BeanWrapperEnumTests { @Test public void testStandardEnumMapWithAutoGrowing() { - GenericBean gb = new GenericBean(); + GenericBean gb = new GenericBean<>(); BeanWrapper bw = new BeanWrapperImpl(gb); bw.setAutoGrowNestedPaths(true); assertNull(gb.getStandardEnumMap()); @@ -173,4 +173,32 @@ public final class BeanWrapperEnumTests { assertEquals(new Integer(1), gb.getStandardEnumMap().get(CustomEnum.VALUE_1)); } + @Test + public void testNonPublicEnum() { + NonPublicEnumHolder holder = new NonPublicEnumHolder(); + BeanWrapper bw = new BeanWrapperImpl(holder); + bw.setPropertyValue("nonPublicEnum", "VALUE_1"); + assertEquals(NonPublicEnum.VALUE_1, holder.getNonPublicEnum()); + } + + + enum NonPublicEnum { + + VALUE_1, VALUE_2; + } + + + static class NonPublicEnumHolder { + + private NonPublicEnum nonPublicEnum; + + public NonPublicEnum getNonPublicEnum() { + return nonPublicEnum; + } + + public void setNonPublicEnum(NonPublicEnum nonPublicEnum) { + this.nonPublicEnum = nonPublicEnum; + } + } + } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java index fb0c1b408b..0a61012a60 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -2735,6 +2735,16 @@ public class DefaultListableBeanFactoryTests { assertSame(Optional.empty(), bf.getBean(Optional.class)); } + @Test + public void testNonPublicEnum() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + RootBeanDefinition bd = new RootBeanDefinition(NonPublicEnumHolder.class); + bd.getConstructorArgumentValues().addGenericArgumentValue("VALUE_1"); + bf.registerBeanDefinition("holderBean", bd); + NonPublicEnumHolder holder = (NonPublicEnumHolder) bf.getBean("holderBean"); + assertEquals(NonPublicEnum.VALUE_1, holder.getNonPublicEnum()); + } + /** * Test that by-type bean lookup caching is working effectively by searching for a * bean of type B 10K times within a container having 1K additional beans of type A. @@ -3262,4 +3272,24 @@ public class DefaultListableBeanFactoryTests { } } + + enum NonPublicEnum { + + VALUE_1, VALUE_2; + } + + + static class NonPublicEnumHolder { + + final NonPublicEnum nonPublicEnum; + + public NonPublicEnumHolder(NonPublicEnum nonPublicEnum) { + this.nonPublicEnum = nonPublicEnum; + } + + public NonPublicEnum getNonPublicEnum() { + return nonPublicEnum; + } + } + }