1010
1111package org .junit .jupiter .api .util ;
1212
13- import java .lang .reflect .AnnotatedElement ;
1413import java .util .Optional ;
1514import java .util .TimeZone ;
1615
1716import org .junit .jupiter .api .extension .AfterEachCallback ;
17+ import org .junit .jupiter .api .extension .BeforeAllCallback ;
1818import org .junit .jupiter .api .extension .BeforeEachCallback ;
1919import org .junit .jupiter .api .extension .ExtensionConfigurationException ;
2020import org .junit .jupiter .api .extension .ExtensionContext ;
2121import org .junit .jupiter .api .extension .ExtensionContext .Namespace ;
22- import org .junit .jupiter .api .extension .ExtensionContext .Store ;
2322import org .junit .jupiter .api .util .TimeZoneProvider .NullTimeZoneProvider ;
2423import org .junit .platform .commons .support .AnnotationSupport ;
2524import org .junit .platform .commons .support .ReflectionSupport ;
2625
27- class DefaultTimeZoneExtension implements BeforeEachCallback , AfterEachCallback {
26+ class DefaultTimeZoneExtension implements BeforeAllCallback , BeforeEachCallback , AfterEachCallback {
2827
2928 private static final Namespace NAMESPACE = Namespace .create (DefaultTimeZoneExtension .class );
3029
31- private static final String KEY = "DefaultTimeZone" ;
30+ private static final String CUSTOM_KEY = "CustomTimeZone" ;
31+ private static final String DEFAULT_KEY = "DefaultTimeZone" ;
32+
33+ @ Override
34+ public void beforeAll (ExtensionContext context ) throws Exception {
35+ createTimeZoneFromAnnotation (context ) //
36+ .ifPresent (timeZone -> store (context , CUSTOM_KEY , timeZone ));
37+ }
3238
3339 @ Override
3440 public void beforeEach (ExtensionContext context ) {
35- AnnotatedElement element = context .getElement ().orElse (null );
36- AnnotationSupport .findAnnotation (element , DefaultTimeZone .class ).ifPresent (
37- annotation -> setDefaultTimeZone (context .getStore (NAMESPACE ), annotation ));
41+ createTimeZoneFromAnnotation (context ) //
42+ .or (() -> load (context , CUSTOM_KEY )) //
43+ .ifPresent (timeZone -> setDefaultTimeZone (context , timeZone ));
44+ }
45+
46+ private void setDefaultTimeZone (ExtensionContext context , TimeZone customTimeZone ) {
47+ store (context , DEFAULT_KEY , TimeZone .getDefault ());
48+ TimeZone .setDefault (customTimeZone );
3849 }
3950
40- private void setDefaultTimeZone (Store store , DefaultTimeZone annotation ) {
51+ private static Optional <TimeZone > createTimeZoneFromAnnotation (ExtensionContext context ) {
52+ return AnnotationSupport .findAnnotation (context .getElement (), DefaultTimeZone .class ) //
53+ .map (DefaultTimeZoneExtension ::createTimeZone );
54+ }
55+
56+ private static TimeZone createTimeZone (DefaultTimeZone annotation ) {
4157 validateCorrectConfiguration (annotation );
42- TimeZone defaultTimeZone ;
43- if (annotation .timeZoneProvider () != NullTimeZoneProvider .class )
44- defaultTimeZone = createTimeZone (annotation .timeZoneProvider ());
45- else
46- defaultTimeZone = createTimeZone (annotation .value ());
47- // defer storing the current default time zone until the new time zone could be created from the configuration
48- // (this prevents cases where misconfigured extensions store default time zone now and restore it later,
49- // which leads to race conditions in our tests)
50- storeDefaultTimeZone (store );
51- TimeZone .setDefault (defaultTimeZone );
58+
59+ if (!annotation .value ().isEmpty ()) {
60+ return createTimeZoneFromZoneId (annotation .value ());
61+ }
62+ else {
63+ return createTimeZoneFromProvider (annotation .timeZoneProvider ());
64+ }
5265 }
5366
5467 private static void validateCorrectConfiguration (DefaultTimeZone annotation ) {
5568 boolean noValue = annotation .value ().isEmpty ();
5669 boolean noProvider = annotation .timeZoneProvider () == NullTimeZoneProvider .class ;
57- if (noValue == noProvider )
70+ if (noValue == noProvider ) {
5871 throw new ExtensionConfigurationException (
59- "Either a valid time zone id or a TimeZoneProvider must be provided to " + DefaultTimeZone .class .getSimpleName ());
72+ "Either a valid time zone id or a TimeZoneProvider must be provided to "
73+ + DefaultTimeZone .class .getSimpleName ());
74+ }
6075 }
6176
62- private static TimeZone createTimeZone (String timeZoneId ) {
77+ private static TimeZone createTimeZoneFromZoneId (String timeZoneId ) {
6378 TimeZone configuredTimeZone = TimeZone .getTimeZone (timeZoneId );
6479 // TimeZone::getTimeZone returns with GMT as fallback if the given ID cannot be understood
6580 if (configuredTimeZone .equals (TimeZone .getTimeZone ("GMT" )) && !"GMT" .equals (timeZoneId )) {
@@ -72,33 +87,32 @@ private static TimeZone createTimeZone(String timeZoneId) {
7287 return configuredTimeZone ;
7388 }
7489
75- private static TimeZone createTimeZone (Class <? extends TimeZoneProvider > providerClass ) {
90+ private static TimeZone createTimeZoneFromProvider (Class <? extends TimeZoneProvider > providerClass ) {
7691 try {
7792 TimeZoneProvider provider = ReflectionSupport .newInstance (providerClass );
7893 return Optional .ofNullable (provider .get ()).orElse (TimeZone .getTimeZone ("GMT" ));
7994 }
8095 catch (Exception exception ) {
8196 throw new ExtensionConfigurationException ("Could not instantiate TimeZoneProvider because of exception" ,
82- exception );
97+ exception );
8398 }
8499 }
85100
86- private void storeDefaultTimeZone (Store store ) {
87- store .put (KEY , TimeZone .getDefault ());
88- }
89-
90101 @ Override
91102 public void afterEach (ExtensionContext context ) {
92- AnnotatedElement element = context .getElement ().orElse (null );
93- AnnotationSupport .findAnnotation (element , DefaultTimeZone .class ).ifPresent (
94- __ -> resetDefaultTimeZone (context .getStore (NAMESPACE )));
103+ load (context , DEFAULT_KEY ).ifPresent (TimeZone ::setDefault );
104+ }
105+
106+ private static void store (ExtensionContext context , String key , TimeZone value ) {
107+ getStore (context ).put (key , value );
108+ }
109+
110+ private static Optional <TimeZone > load (ExtensionContext context , String key ) {
111+ return Optional .ofNullable (getStore (context ).get (key , TimeZone .class ));
95112 }
96113
97- private void resetDefaultTimeZone (Store store ) {
98- TimeZone timeZone = store .get (KEY , TimeZone .class );
99- // default time zone is null if the extension was misconfigured and execution failed in "before"
100- if (timeZone != null )
101- TimeZone .setDefault (timeZone );
114+ private static ExtensionContext .Store getStore (ExtensionContext context ) {
115+ return context .getStore (NAMESPACE );
102116 }
103117
104118}
0 commit comments