• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TAKETODAY / today-infrastructure / 18154768944

01 Oct 2025 07:26AM UTC coverage: 81.882% (-0.005%) from 81.887%
18154768944

push

github

web-flow
Merge pull request #290 from TAKETODAY/dev/jspecify

jspecify

59788 of 78013 branches covered (76.64%)

Branch coverage included in aggregate %.

141239 of 167496 relevant lines covered (84.32%)

3.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.24
today-context/src/main/java/infra/context/support/ApplicationObjectSupport.java
1
/*
2
 * Copyright 2017 - 2025 the original author or authors.
3
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see [https://www.gnu.org/licenses/]
16
 */
17

18
package infra.context.support;
19

20
import org.jspecify.annotations.Nullable;
21

22
import infra.beans.BeansException;
23
import infra.context.ApplicationContext;
24
import infra.context.ApplicationContextAware;
25
import infra.context.ApplicationContextException;
26
import infra.lang.Assert;
27
import infra.logging.Logger;
28
import infra.logging.LoggerFactory;
29

30
/**
31
 * Convenient superclass for application objects that want to be aware of
32
 * the application context, e.g. for custom lookup of collaborating beans
33
 * or for context-specific resource access. It saves the application
34
 * context reference and provides an initialization callback method.
35
 * Furthermore, it offers numerous convenience methods for message lookup.
36
 *
37
 * <p>There is no requirement to subclass this class: It just makes things
38
 * a little easier if you need access to the context, e.g. for access to
39
 * file resources or to the message source. Note that many application
40
 * objects do not need to be aware of the application context at all,
41
 * as they can receive collaborating beans via bean references.
42
 *
43
 * <p>Many framework classes are derived from this class, particularly
44
 * within the web support.
45
 *
46
 * @author Rod Johnson
47
 * @author Juergen Hoeller
48
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
49
 * @since 2019-12-21 15:45
50
 */
51
public abstract class ApplicationObjectSupport implements ApplicationContextAware {
2✔
52

53
  protected final Logger logger = LoggerFactory.getLogger(getClass());
6✔
54

55
  @Nullable
56
  protected ApplicationContext applicationContext;
57

58
  /** MessageSourceAccessor for easy message access. @since 4.0 */
59
  @Nullable
60
  protected MessageSourceAccessor messageSourceAccessor;
61

62
  @Override
63
  public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
64
    if (context == null && !isContextRequired()) {
5✔
65
      // Reset internal context state.
66
      this.applicationContext = null;
3✔
67
      this.messageSourceAccessor = null;
4✔
68
    }
69
    else if (this.applicationContext == null) {
3✔
70
      // Initialize with passed-in context.
71
      if (!requiredContextClass().isInstance(context)) {
5✔
72
        throw new ApplicationContextException(
8✔
73
                "Invalid application context: needs to be of type [%s]".formatted(requiredContextClass().getName()));
6✔
74
      }
75
      this.applicationContext = context;
3✔
76
      initApplicationContext(context);
4✔
77
    }
78
    else {
79
      // Ignore reinitialization if same context passed in.
80
      if (this.applicationContext != context) {
4✔
81
        throw new ApplicationContextException("Cannot reinitialize with different application context: current one is [%s], passed-in one is [%s]"
14✔
82
                .formatted(this.applicationContext, context));
3✔
83
      }
84
    }
85
  }
1✔
86

87
  /**
88
   * Subclasses can override this for custom initialization behavior. Gets called
89
   * by {@code setApplicationContext} after setting the context instance.
90
   * <p>
91
   * Note: Does <i>not</i> get called on re-initialization of the context but
92
   * rather just on first initialization of this object's context reference.
93
   * <p>
94
   * The default implementation calls the overloaded
95
   * {@link #initApplicationContext()} method without ApplicationContext
96
   * reference.
97
   *
98
   * @param context the containing ApplicationContext
99
   * @throws ApplicationContextException if thrown by ApplicationContext methods
100
   * @see #setApplicationContext
101
   */
102
  protected void initApplicationContext(ApplicationContext context) {
103
    initApplicationContext();
2✔
104
  }
1✔
105

106
  /**
107
   * Subclasses can override this for custom initialization behavior.
108
   * <p>
109
   * The default implementation is empty. Called by
110
   * {@link #initApplicationContext(ApplicationContext)}.
111
   *
112
   * @throws ApplicationContextException if thrown by ApplicationContext methods
113
   * @see #setApplicationContext
114
   */
115
  protected void initApplicationContext() {
116
  }
1✔
117

118
  /**
119
   * Return the ApplicationContext that this object is associated with.
120
   *
121
   * @throws IllegalStateException if not running in an ApplicationContext
122
   */
123
  @Nullable
124
  public final ApplicationContext getApplicationContext() throws IllegalStateException {
125
    ApplicationContext context = this.applicationContext;
3✔
126
    if (context == null && isContextRequired()) {
5!
127
      throw new IllegalStateException(
×
128
              "ApplicationContextSupport instance [%s] does not run in an ApplicationContext".formatted(this));
×
129
    }
130
    return context;
2✔
131
  }
132

133
  /**
134
   * Return the ApplicationContext that this object is associated with.
135
   *
136
   * @throws IllegalStateException if not running in an ApplicationContext
137
   */
138
  public ApplicationContext obtainApplicationContext() {
139
    final ApplicationContext context = this.applicationContext;
3✔
140
    Assert.state(context != null, "No ApplicationContext");
7✔
141
    return context;
2✔
142
  }
143

144
  /**
145
   * unwrap bean-factory to {@code requiredType}
146
   *
147
   * @throws IllegalArgumentException not a requiredType
148
   * @see ApplicationContext#getBeanFactory()
149
   * @since 4.0
150
   */
151
  public <T> T unwrapFactory(Class<T> requiredType) {
152
    return obtainApplicationContext().unwrapFactory(requiredType);
5✔
153
  }
154

155
  /**
156
   * unwrap this ApplicationContext to {@code requiredType}
157
   *
158
   * @throws IllegalArgumentException not a requiredType
159
   * @since 4.0
160
   */
161
  public <T> T unwrapContext(Class<T> requiredType) {
162
    return obtainApplicationContext().unwrap(requiredType);
5✔
163
  }
164

165
  /**
166
   * Return a MessageSourceAccessor for the application context
167
   * used by this object, for easy message access.
168
   *
169
   * @throws IllegalStateException if not running in an ApplicationContext
170
   * @since 4.0
171
   */
172
  @Nullable
173
  protected final MessageSourceAccessor getMessageSourceAccessor() throws IllegalStateException {
174
    MessageSourceAccessor accessor = this.messageSourceAccessor;
3✔
175
    if (accessor == null) {
2✔
176
      ApplicationContext context = this.applicationContext;
3✔
177
      if (context == null) {
2✔
178
        if (isContextRequired()) {
3✔
179
          throw new IllegalStateException(
9✔
180
                  "ApplicationObjectSupport instance [%s] does not run in an ApplicationContext".formatted(this));
3✔
181
        }
182
        return null;
2✔
183
      }
184
      else {
185
        accessor = new MessageSourceAccessor(context);
5✔
186
        this.messageSourceAccessor = accessor;
3✔
187
      }
188
    }
189

190
    return accessor;
2✔
191
  }
192

193
  /**
194
   * Determine whether this application object needs to run in an ApplicationContext.
195
   * <p>Default is "false". Can be overridden to enforce running in a context
196
   * (i.e. to throw IllegalStateException on accessors if outside a context).
197
   *
198
   * @see #getApplicationContext
199
   * @see #getMessageSourceAccessor
200
   * @since 4.0
201
   */
202
  protected boolean isContextRequired() {
203
    return false;
2✔
204
  }
205

206
  /**
207
   * Determine the context class that any context passed to
208
   * {@code setApplicationContext} must be an instance of.
209
   * Can be overridden in subclasses.
210
   *
211
   * @see #setApplicationContext
212
   * @since 4.0
213
   */
214
  protected Class<?> requiredContextClass() {
215
    return ApplicationContext.class;
2✔
216
  }
217
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc