• 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

90.0
today-context/src/main/java/infra/instrument/classloading/ReflectiveLoadTimeWeaver.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.instrument.classloading;
19

20
import org.jspecify.annotations.Nullable;
21

22
import java.lang.instrument.ClassFileTransformer;
23
import java.lang.reflect.Method;
24

25
import infra.core.DecoratingClassLoader;
26
import infra.core.OverridingClassLoader;
27
import infra.lang.Assert;
28
import infra.logging.Logger;
29
import infra.logging.LoggerFactory;
30
import infra.util.ClassUtils;
31
import infra.util.ReflectionUtils;
32

33
/**
34
 * {@link LoadTimeWeaver} which uses reflection to delegate to an underlying ClassLoader
35
 * with well-known transformation hooks. The underlying ClassLoader is expected to
36
 * support the following weaving methods (as defined in the {@link LoadTimeWeaver}
37
 * interface):
38
 * <ul>
39
 * <li>{@code public void addTransformer(java.lang.instrument.ClassFileTransformer)}:
40
 * for registering the given ClassFileTransformer on this ClassLoader
41
 * <li>{@code public ClassLoader getThrowawayClassLoader()}:
42
 * for obtaining a throwaway class loader for this ClassLoader (optional;
43
 * ReflectiveLoadTimeWeaver will fall back to a SimpleThrowawayClassLoader if
44
 * that method isn't available)
45
 * </ul>
46
 *
47
 * <p>Please note that the above methods <i>must</i> reside in a class that is
48
 * publicly accessible, although the class itself does not have to be visible
49
 * to the application's class loader.
50
 *
51
 * <p>The reflective nature of this LoadTimeWeaver is particularly useful when the
52
 * underlying ClassLoader implementation is loaded in a different class loader itself
53
 * (such as the application server's class loader which is not visible to the
54
 * web application). There is no direct API dependency between this LoadTimeWeaver
55
 * adapter and the underlying ClassLoader, just a 'loose' method contract.
56
 *
57
 * <p>This is the LoadTimeWeaver to use e.g. with the Resin application server
58
 * version 3.1+.
59
 *
60
 * @author Costin Leau
61
 * @author Juergen Hoeller
62
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
63
 * @see #addTransformer(ClassFileTransformer)
64
 * @see #getThrowawayClassLoader()
65
 * @see SimpleThrowawayClassLoader
66
 * @since 4.0
67
 */
68
public class ReflectiveLoadTimeWeaver implements LoadTimeWeaver {
69

70
  private static final Logger log = LoggerFactory.getLogger(ReflectiveLoadTimeWeaver.class);
4✔
71

72
  private static final String ADD_TRANSFORMER_METHOD_NAME = "addTransformer";
73

74
  private static final String GET_THROWAWAY_CLASS_LOADER_METHOD_NAME = "getThrowawayClassLoader";
75

76
  private final ClassLoader classLoader;
77

78
  private final Method addTransformerMethod;
79

80
  @Nullable
81
  private final Method getThrowawayClassLoaderMethod;
82

83
  /**
84
   * Create a new ReflectiveLoadTimeWeaver for the current context class
85
   * loader, <i>which needs to support the required weaving methods</i>.
86
   */
87
  public ReflectiveLoadTimeWeaver() {
88
    this(ClassUtils.getDefaultClassLoader());
3✔
89
  }
1✔
90

91
  /**
92
   * Create a new SimpleLoadTimeWeaver for the given class loader.
93
   *
94
   * @param classLoader the {@code ClassLoader} to delegate to for
95
   * weaving (<i>must</i> support the required weaving methods).
96
   * @throws IllegalStateException if the supplied {@code ClassLoader}
97
   * does not support the required weaving methods
98
   */
99
  public ReflectiveLoadTimeWeaver(@Nullable ClassLoader classLoader) {
2✔
100
    Assert.notNull(classLoader, "ClassLoader is required");
3✔
101
    this.classLoader = classLoader;
3✔
102

103
    Method addTransformerMethod = ReflectionUtils.getMethodIfAvailable(
4✔
104
            this.classLoader.getClass(), ADD_TRANSFORMER_METHOD_NAME, ClassFileTransformer.class);
8✔
105
    if (addTransformerMethod == null) {
2✔
106
      throw new IllegalStateException(
8✔
107
              "ClassLoader [%s] does NOT provide an 'addTransformer(ClassFileTransformer)' method."
108
                      .formatted(classLoader.getClass().getName()));
6✔
109
    }
110
    this.addTransformerMethod = addTransformerMethod;
3✔
111

112
    Method getThrowawayClassLoaderMethod = ReflectionUtils.getMethodIfAvailable(
4✔
113
            this.classLoader.getClass(), GET_THROWAWAY_CLASS_LOADER_METHOD_NAME);
4✔
114
    // getThrowawayClassLoader method is optional
115
    if (getThrowawayClassLoaderMethod == null) {
2✔
116
      if (log.isDebugEnabled()) {
3!
117
        log.debug("The ClassLoader [{}] does NOT provide a " +
×
118
                        "'getThrowawayClassLoader()' method; SimpleThrowawayClassLoader will be used instead.",
119
                classLoader.getClass().getName());
×
120
      }
121
    }
122
    this.getThrowawayClassLoaderMethod = getThrowawayClassLoaderMethod;
3✔
123
  }
1✔
124

125
  @Override
126
  public void addTransformer(ClassFileTransformer transformer) {
127
    Assert.notNull(transformer, "Transformer is required");
3✔
128
    ReflectionUtils.invokeMethod(this.addTransformerMethod, this.classLoader, transformer);
12✔
129
  }
1✔
130

131
  @Override
132
  public ClassLoader getInstrumentableClassLoader() {
133
    return this.classLoader;
3✔
134
  }
135

136
  @Override
137
  public ClassLoader getThrowawayClassLoader() {
138
    if (this.getThrowawayClassLoaderMethod != null) {
3✔
139
      ClassLoader target = (ClassLoader)
4✔
140
              ReflectionUtils.invokeMethod(this.getThrowawayClassLoaderMethod, this.classLoader);
3✔
141
      return (target instanceof DecoratingClassLoader ? target :
4!
142
              new OverridingClassLoader(this.classLoader, target));
6✔
143
    }
144
    else {
145
      return new SimpleThrowawayClassLoader(this.classLoader);
6✔
146
    }
147
  }
148

149
}
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