1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.api.plugin.testing;
20
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.Reader;
26 import java.io.StringReader;
27 import java.lang.reflect.AccessibleObject;
28 import java.lang.reflect.AnnotatedElement;
29 import java.lang.reflect.Field;
30 import java.net.URL;
31 import java.nio.file.Files;
32 import java.nio.file.Path;
33 import java.nio.file.Paths;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.HashMap;
37 import java.util.LinkedHashSet;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Objects;
41 import java.util.Optional;
42 import java.util.Set;
43 import java.util.stream.Collectors;
44 import java.util.stream.Stream;
45
46 import org.apache.maven.api.MojoExecution;
47 import org.apache.maven.api.Project;
48 import org.apache.maven.api.Session;
49 import org.apache.maven.api.di.Named;
50 import org.apache.maven.api.di.Priority;
51 import org.apache.maven.api.di.Provides;
52 import org.apache.maven.api.di.Singleton;
53 import org.apache.maven.api.di.testing.MavenDIExtension;
54 import org.apache.maven.api.model.Build;
55 import org.apache.maven.api.model.ConfigurationContainer;
56 import org.apache.maven.api.model.Model;
57 import org.apache.maven.api.model.Source;
58 import org.apache.maven.api.plugin.Log;
59 import org.apache.maven.api.plugin.Mojo;
60 import org.apache.maven.api.plugin.descriptor.MojoDescriptor;
61 import org.apache.maven.api.plugin.descriptor.Parameter;
62 import org.apache.maven.api.plugin.descriptor.PluginDescriptor;
63 import org.apache.maven.api.plugin.testing.stubs.MojoExecutionStub;
64 import org.apache.maven.api.plugin.testing.stubs.PluginStub;
65 import org.apache.maven.api.plugin.testing.stubs.ProducedArtifactStub;
66 import org.apache.maven.api.plugin.testing.stubs.ProjectStub;
67 import org.apache.maven.api.plugin.testing.stubs.RepositorySystemSupplier;
68 import org.apache.maven.api.plugin.testing.stubs.SessionMock;
69 import org.apache.maven.api.services.ArtifactDeployer;
70 import org.apache.maven.api.services.ArtifactFactory;
71 import org.apache.maven.api.services.ArtifactInstaller;
72 import org.apache.maven.api.services.ArtifactManager;
73 import org.apache.maven.api.services.LocalRepositoryManager;
74 import org.apache.maven.api.services.ProjectBuilder;
75 import org.apache.maven.api.services.ProjectManager;
76 import org.apache.maven.api.services.RepositoryFactory;
77 import org.apache.maven.api.services.VersionParser;
78 import org.apache.maven.api.services.xml.ModelXmlFactory;
79 import org.apache.maven.api.xml.XmlNode;
80 import org.apache.maven.api.xml.XmlService;
81 import org.apache.maven.configuration.internal.EnhancedComponentConfigurator;
82 import org.apache.maven.di.Injector;
83 import org.apache.maven.di.Key;
84 import org.apache.maven.di.impl.DIException;
85 import org.apache.maven.impl.InternalSession;
86 import org.apache.maven.impl.model.DefaultModelPathTranslator;
87 import org.apache.maven.impl.model.DefaultPathTranslator;
88 import org.apache.maven.internal.impl.DefaultLog;
89 import org.apache.maven.internal.xml.XmlPlexusConfiguration;
90 import org.apache.maven.lifecycle.internal.MojoDescriptorCreator;
91 import org.apache.maven.model.v4.MavenMerger;
92 import org.apache.maven.model.v4.MavenStaxReader;
93 import org.apache.maven.plugin.PluginParameterExpressionEvaluatorV4;
94 import org.apache.maven.plugin.descriptor.io.PluginDescriptorStaxReader;
95 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
96 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
97 import org.codehaus.plexus.component.configurator.expression.TypeAwareExpressionEvaluator;
98 import org.codehaus.plexus.util.ReflectionUtils;
99 import org.codehaus.plexus.util.xml.XmlStreamReader;
100 import org.codehaus.plexus.util.xml.Xpp3Dom;
101 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
102 import org.eclipse.aether.RepositorySystem;
103 import org.junit.jupiter.api.extension.BeforeEachCallback;
104 import org.junit.jupiter.api.extension.ExtensionContext;
105 import org.junit.jupiter.api.extension.ParameterContext;
106 import org.junit.jupiter.api.extension.ParameterResolutionException;
107 import org.junit.jupiter.api.extension.ParameterResolver;
108 import org.junit.platform.commons.support.AnnotationSupport;
109 import org.slf4j.LoggerFactory;
110
111 import static java.util.Objects.requireNonNull;
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166 public class MojoExtension extends MavenDIExtension implements ParameterResolver, BeforeEachCallback {
167
168
169 protected static String pluginBasedir;
170
171
172 protected static String basedir;
173
174
175
176
177
178
179
180 public static String getTestId() {
181 return context.getRequiredTestClass().getSimpleName() + "-"
182 + context.getRequiredTestMethod().getName();
183 }
184
185
186
187
188
189
190
191
192 public static String getBasedir() {
193 return requireNonNull(basedir != null ? basedir : MavenDIExtension.basedir);
194 }
195
196
197
198
199
200
201
202 public static String getPluginBasedir() {
203 return requireNonNull(pluginBasedir);
204 }
205
206
207
208
209
210
211
212
213
214
215 @Override
216 public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
217 throws ParameterResolutionException {
218 return parameterContext.isAnnotated(InjectMojo.class)
219 || parameterContext.getDeclaringExecutable().isAnnotationPresent(InjectMojo.class);
220 }
221
222 @Override
223 public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
224 throws ParameterResolutionException {
225 try {
226 Class<?> holder = parameterContext.getTarget().orElseThrow().getClass();
227 PluginDescriptor descriptor = extensionContext
228 .getStore(ExtensionContext.Namespace.GLOBAL)
229 .get(PluginDescriptor.class, PluginDescriptor.class);
230 Model model =
231 extensionContext.getStore(ExtensionContext.Namespace.GLOBAL).get(Model.class, Model.class);
232 InjectMojo parameterInjectMojo =
233 parameterContext.getAnnotatedElement().getAnnotation(InjectMojo.class);
234 String goal;
235 if (parameterInjectMojo != null) {
236 String pom = parameterInjectMojo.pom();
237 if (pom != null && !pom.isEmpty()) {
238 try (Reader r = openPomUrl(holder, pom, new Path[1])) {
239 Model localModel = new MavenStaxReader().read(r);
240 model = new MavenMerger().merge(localModel, model, false, null);
241 model = new DefaultModelPathTranslator(new DefaultPathTranslator())
242 .alignToBaseDirectory(model, Paths.get(getBasedir()), null);
243 }
244 }
245 goal = parameterInjectMojo.goal();
246 } else {
247 InjectMojo methodInjectMojo = AnnotationSupport.findAnnotation(
248 parameterContext.getDeclaringExecutable(), InjectMojo.class)
249 .orElse(null);
250 if (methodInjectMojo != null) {
251 goal = methodInjectMojo.goal();
252 } else {
253 goal = getGoalFromMojoImplementationClass(
254 parameterContext.getParameter().getType());
255 }
256 }
257
258 Set<MojoParameter> mojoParameters = new LinkedHashSet<>();
259 for (AnnotatedElement ae :
260 Arrays.asList(parameterContext.getDeclaringExecutable(), parameterContext.getAnnotatedElement())) {
261 mojoParameters.addAll(AnnotationSupport.findRepeatableAnnotations(ae, MojoParameter.class));
262 }
263 String[] coord = mojoCoordinates(goal);
264
265 XmlNode pluginConfiguration = model.getBuild().getPlugins().stream()
266 .filter(p ->
267 Objects.equals(p.getGroupId(), coord[0]) && Objects.equals(p.getArtifactId(), coord[1]))
268 .map(ConfigurationContainer::getConfiguration)
269 .findFirst()
270 .orElseGet(() -> XmlNode.newInstance("config"));
271 List<XmlNode> children = mojoParameters.stream()
272 .map(mp -> XmlNode.newInstance(mp.name(), mp.value()))
273 .collect(Collectors.toList());
274 XmlNode config = XmlNode.newInstance("configuration", null, null, children, null);
275 pluginConfiguration = XmlService.merge(config, pluginConfiguration);
276
277
278
279 Mojo mojo = lookup(Mojo.class, coord[0] + ":" + coord[1] + ":" + coord[2] + ":" + coord[3]);
280 for (MojoDescriptor mojoDescriptor : descriptor.getMojos()) {
281 if (Objects.equals(mojoDescriptor.getGoal(), coord[3])) {
282 if (pluginConfiguration != null) {
283 pluginConfiguration = finalizeConfig(pluginConfiguration, mojoDescriptor);
284 }
285 }
286 }
287
288 Session session = getInjector().getInstance(Session.class);
289 Project project = getInjector().getInstance(Project.class);
290 MojoExecution mojoExecution = getInjector().getInstance(MojoExecution.class);
291 ExpressionEvaluator evaluator = new WrapEvaluator(
292 getInjector(), new PluginParameterExpressionEvaluatorV4(session, project, mojoExecution));
293
294 EnhancedComponentConfigurator configurator = new EnhancedComponentConfigurator();
295 configurator.configureComponent(
296 mojo, new XmlPlexusConfiguration(pluginConfiguration), evaluator, null, null);
297 return mojo;
298 } catch (Exception e) {
299 throw new ParameterResolutionException("Unable to resolve mojo", e);
300 }
301 }
302
303
304
305
306
307
308 private static String getGoalFromMojoImplementationClass(Class<?> cl) throws IOException {
309 return cl.getAnnotation(Named.class).value();
310 }
311
312 @Override
313 @SuppressWarnings("checkstyle:MethodLength")
314 public void beforeEach(ExtensionContext context) throws Exception {
315 if (pluginBasedir == null) {
316 pluginBasedir = MavenDIExtension.getBasedir();
317 }
318 basedir = AnnotationSupport.findAnnotation(context.getElement().orElseThrow(), Basedir.class)
319 .map(Basedir::value)
320 .orElse(pluginBasedir);
321 if (basedir != null) {
322 if (basedir.isEmpty()) {
323 basedir = pluginBasedir + "/target/tests/"
324 + context.getRequiredTestClass().getSimpleName() + "/"
325 + context.getRequiredTestMethod().getName();
326 } else {
327 basedir = basedir.replace("${basedir}", pluginBasedir);
328 }
329 }
330
331 setContext(context);
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365 Path basedirPath = Paths.get(getBasedir());
366
367 InjectMojo mojo = AnnotationSupport.findAnnotation(context.getElement().get(), InjectMojo.class)
368 .orElse(null);
369 Model defaultModel = Model.newBuilder()
370 .groupId("myGroupId")
371 .artifactId("myArtifactId")
372 .version("1.0-SNAPSHOT")
373 .packaging("jar")
374 .build(Build.newBuilder()
375 .directory(basedirPath.resolve("target").toString())
376 .outputDirectory(basedirPath.resolve("target/classes").toString())
377 .sources(List.of(
378 Source.newBuilder()
379 .scope("main")
380 .lang("java")
381 .directory(basedirPath
382 .resolve("src/main/java")
383 .toString())
384 .build(),
385 Source.newBuilder()
386 .scope("test")
387 .lang("java")
388 .directory(basedirPath
389 .resolve("src/test/java")
390 .toString())
391 .build()))
392 .testOutputDirectory(
393 basedirPath.resolve("target/test-classes").toString())
394 .build())
395 .build();
396 Path[] modelPath = new Path[] {null};
397 Model tmodel = null;
398 if (mojo != null) {
399 String pom = mojo.pom();
400 if (pom != null && !pom.isEmpty()) {
401 try (Reader r = openPomUrl(context.getRequiredTestClass(), pom, modelPath)) {
402 tmodel = new MavenStaxReader().read(r);
403 }
404 } else {
405 Path pomPath = basedirPath.resolve("pom.xml");
406 if (Files.exists(pomPath)) {
407 try (Reader r = Files.newBufferedReader(pomPath)) {
408 tmodel = new MavenStaxReader().read(r);
409 modelPath[0] = pomPath;
410 }
411 }
412 }
413 }
414 Model model;
415 if (tmodel == null) {
416 model = defaultModel;
417 } else {
418 model = new MavenMerger().merge(tmodel, defaultModel, false, null);
419 }
420 tmodel = new DefaultModelPathTranslator(new DefaultPathTranslator())
421 .alignToBaseDirectory(tmodel, Paths.get(getBasedir()), null);
422 context.getStore(ExtensionContext.Namespace.GLOBAL).put(Model.class, tmodel);
423
424
425
426 PluginDescriptor pluginDescriptor;
427 ClassLoader classLoader = context.getRequiredTestClass().getClassLoader();
428 try (InputStream is = requireNonNull(
429 classLoader.getResourceAsStream(getPluginDescriptorLocation()),
430 "Unable to find plugin descriptor: " + getPluginDescriptorLocation());
431 Reader reader = new BufferedReader(new XmlStreamReader(is))) {
432
433 pluginDescriptor = new PluginDescriptorStaxReader().read(reader);
434 }
435 context.getStore(ExtensionContext.Namespace.GLOBAL).put(PluginDescriptor.class, pluginDescriptor);
436
437
438
439
440 @SuppressWarnings({"unused", "MagicNumber"})
441 class Foo {
442
443 @Provides
444 @Singleton
445 @Priority(-10)
446 private InternalSession createSession() {
447 MojoTest mojoTest = context.getRequiredTestClass().getAnnotation(MojoTest.class);
448 if (mojoTest != null && mojoTest.realSession()) {
449
450 try {
451 Class<?> apiRunner = Class.forName("org.apache.maven.impl.standalone.ApiRunner");
452 Object session = apiRunner.getMethod("createSession").invoke(null);
453 return (InternalSession) session;
454 } catch (Throwable t) {
455
456 throw new org.opentest4j.TestAbortedException(
457 "@MojoTest(realSession=true) requested but could not create a real session.", t);
458 }
459 }
460 return SessionMock.getMockSession(getBasedir());
461 }
462
463 @Provides
464 @Singleton
465 @Priority(-10)
466 private Project createProject(InternalSession s) {
467 ProjectStub stub = new ProjectStub();
468 if (!"pom".equals(model.getPackaging())) {
469 ProducedArtifactStub artifact = new ProducedArtifactStub(
470 model.getGroupId(), model.getArtifactId(), "", model.getVersion(), model.getPackaging());
471 stub.setMainArtifact(artifact);
472 }
473 stub.setModel(model);
474 stub.setBasedir(Paths.get(MojoExtension.getBasedir()));
475 stub.setPomPath(modelPath[0]);
476 s.getService(ArtifactManager.class).setPath(stub.getPomArtifact(), modelPath[0]);
477 return stub;
478 }
479
480 @Provides
481 @Singleton
482 @Priority(-10)
483 private MojoExecution createMojoExecution() {
484 MojoExecutionStub mes = new MojoExecutionStub("executionId", null);
485 if (mojo != null) {
486 String goal = mojo.goal();
487 int idx = goal.lastIndexOf(':');
488 if (idx >= 0) {
489 goal = goal.substring(idx + 1);
490 }
491 mes.setGoal(goal);
492 for (MojoDescriptor md : pluginDescriptor.getMojos()) {
493 if (goal.equals(md.getGoal())) {
494 mes.setDescriptor(md);
495 }
496 }
497 requireNonNull(mes.getDescriptor());
498 }
499 PluginStub plugin = new PluginStub();
500 plugin.setDescriptor(pluginDescriptor);
501 mes.setPlugin(plugin);
502 return mes;
503 }
504
505 @Provides
506 @Singleton
507 @Priority(-10)
508 private Log createLog() {
509 return new DefaultLog(LoggerFactory.getLogger("anonymous"));
510 }
511
512 @Provides
513 static RepositorySystemSupplier newRepositorySystemSupplier() {
514 return new RepositorySystemSupplier();
515 }
516
517 @Provides
518 static RepositorySystem newRepositorySystem(RepositorySystemSupplier repositorySystemSupplier) {
519 return repositorySystemSupplier.getRepositorySystem();
520 }
521
522 @Provides
523 @Priority(10)
524 static RepositoryFactory newRepositoryFactory(Session session) {
525 return session.getService(RepositoryFactory.class);
526 }
527
528 @Provides
529 @Priority(10)
530 static VersionParser newVersionParser(Session session) {
531 return session.getService(VersionParser.class);
532 }
533
534 @Provides
535 @Priority(10)
536 static LocalRepositoryManager newLocalRepositoryManager(Session session) {
537 return session.getService(LocalRepositoryManager.class);
538 }
539
540 @Provides
541 @Priority(10)
542 static ArtifactInstaller newArtifactInstaller(Session session) {
543 return session.getService(ArtifactInstaller.class);
544 }
545
546 @Provides
547 @Priority(10)
548 static ArtifactDeployer newArtifactDeployer(Session session) {
549 return session.getService(ArtifactDeployer.class);
550 }
551
552 @Provides
553 @Priority(10)
554 static ArtifactManager newArtifactManager(Session session) {
555 return session.getService(ArtifactManager.class);
556 }
557
558 @Provides
559 @Priority(10)
560 static ProjectManager newProjectManager(Session session) {
561 return session.getService(ProjectManager.class);
562 }
563
564 @Provides
565 @Priority(10)
566 static ArtifactFactory newArtifactFactory(Session session) {
567 return session.getService(ArtifactFactory.class);
568 }
569
570 @Provides
571 @Priority(10)
572 static ProjectBuilder newProjectBuilder(Session session) {
573 return session.getService(ProjectBuilder.class);
574 }
575
576 @Provides
577 @Priority(10)
578 static ModelXmlFactory newModelXmlFactory(Session session) {
579 return session.getService(ModelXmlFactory.class);
580 }
581 }
582
583 getInjector().bindInstance(Foo.class, new Foo());
584
585 getInjector().injectInstance(context.getRequiredTestInstance());
586
587
588
589
590
591
592
593
594
595
596 }
597
598 private Reader openPomUrl(Class<?> holder, String pom, Path[] modelPath) throws IOException {
599 if (pom.startsWith("file:")) {
600 Path path = Paths.get(getBasedir()).resolve(pom.substring("file:".length()));
601 modelPath[0] = path;
602 return Files.newBufferedReader(path);
603 } else if (pom.startsWith("classpath:")) {
604 URL url = holder.getResource(pom.substring("classpath:".length()));
605 if (url == null) {
606 throw new IllegalStateException("Unable to find pom on classpath: " + pom);
607 }
608 return new XmlStreamReader(url.openStream());
609 } else if (pom.contains("<project>")) {
610 return new StringReader(pom);
611 } else {
612 Path path = Paths.get(getBasedir()).resolve(pom);
613 modelPath[0] = path;
614 return Files.newBufferedReader(path);
615 }
616 }
617
618 protected String getPluginDescriptorLocation() {
619 return "META-INF/maven/plugin.xml";
620 }
621
622 protected String[] mojoCoordinates(String goal) throws Exception {
623 if (goal.matches(".*:.*:.*:.*")) {
624 return goal.split(":");
625 } else {
626 Path pluginPom = Paths.get(getPluginBasedir(), "pom.xml");
627 Xpp3Dom pluginPomDom = Xpp3DomBuilder.build(Files.newBufferedReader(pluginPom));
628 String artifactId = pluginPomDom.getChild("artifactId").getValue();
629 String groupId = resolveFromRootThenParent(pluginPomDom, "groupId");
630 String version = resolveFromRootThenParent(pluginPomDom, "version");
631 return new String[] {groupId, artifactId, version, goal};
632 }
633 }
634
635 private XmlNode finalizeConfig(XmlNode config, MojoDescriptor mojoDescriptor) {
636 List<XmlNode> children = new ArrayList<>();
637 if (mojoDescriptor != null) {
638 XmlNode defaultConfiguration;
639 defaultConfiguration = MojoDescriptorCreator.convert(mojoDescriptor);
640 for (Parameter parameter : mojoDescriptor.getParameters()) {
641 XmlNode parameterConfiguration = config.child(parameter.getName());
642 if (parameterConfiguration == null) {
643 parameterConfiguration = config.child(parameter.getAlias());
644 }
645 XmlNode parameterDefaults = defaultConfiguration.child(parameter.getName());
646 parameterConfiguration = XmlNode.merge(parameterConfiguration, parameterDefaults, Boolean.TRUE);
647 if (parameterConfiguration != null) {
648 Map<String, String> attributes = new HashMap<>(parameterConfiguration.attributes());
649
650
651
652
653 parameterConfiguration = XmlNode.newInstance(
654 parameter.getName(),
655 parameterConfiguration.value(),
656 attributes,
657 parameterConfiguration.children(),
658 parameterConfiguration.inputLocation());
659
660 children.add(parameterConfiguration);
661 }
662 }
663 }
664 return XmlNode.newInstance("configuration", null, null, children, null);
665 }
666
667 private static Optional<Xpp3Dom> child(Xpp3Dom element, String name) {
668 return Optional.ofNullable(element.getChild(name));
669 }
670
671 private static Stream<Xpp3Dom> children(Xpp3Dom element) {
672 return Stream.of(element.getChildren());
673 }
674
675 public static XmlNode extractPluginConfiguration(String artifactId, Xpp3Dom pomDom) throws Exception {
676 Xpp3Dom pluginConfigurationElement = child(pomDom, "build")
677 .flatMap(buildElement -> child(buildElement, "plugins"))
678 .map(MojoExtension::children)
679 .orElseGet(Stream::empty)
680 .filter(e -> e.getChild("artifactId").getValue().equals(artifactId))
681 .findFirst()
682 .flatMap(buildElement -> child(buildElement, "configuration"))
683 .orElse(Xpp3DomBuilder.build(new StringReader("<configuration/>")));
684 return pluginConfigurationElement.getDom();
685 }
686
687
688
689
690
691
692 private static String resolveFromRootThenParent(Xpp3Dom pluginPomDom, String element) throws Exception {
693 return Optional.ofNullable(child(pluginPomDom, element).orElseGet(() -> child(pluginPomDom, "parent")
694 .flatMap(e -> child(e, element))
695 .orElse(null)))
696 .map(Xpp3Dom::getValue)
697 .orElseThrow(() -> new Exception("unable to determine " + element));
698 }
699
700
701
702
703
704
705 public static Object getVariableValueFromObject(Object object, String variable) throws IllegalAccessException {
706 Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses(variable, object.getClass());
707 field.setAccessible(true);
708 return field.get(object);
709 }
710
711
712
713
714
715
716 public static Map<String, Object> getVariablesAndValuesFromObject(Object object) throws IllegalAccessException {
717 return getVariablesAndValuesFromObject(object.getClass(), object);
718 }
719
720
721
722
723
724
725
726
727 public static Map<String, Object> getVariablesAndValuesFromObject(Class<?> clazz, Object object)
728 throws IllegalAccessException {
729 Map<String, Object> map = new HashMap<>();
730 Field[] fields = clazz.getDeclaredFields();
731 AccessibleObject.setAccessible(fields, true);
732 for (Field field : fields) {
733 map.put(field.getName(), field.get(object));
734 }
735 Class<?> superclass = clazz.getSuperclass();
736 if (!Object.class.equals(superclass)) {
737 map.putAll(getVariablesAndValuesFromObject(superclass, object));
738 }
739 return map;
740 }
741
742
743
744
745 public static void setVariableValueToObject(Object object, String variable, Object value)
746 throws IllegalAccessException {
747 Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses(variable, object.getClass());
748 requireNonNull(field, "Field " + variable + " not found");
749 field.setAccessible(true);
750 field.set(object, value);
751 }
752
753 static class WrapEvaluator implements TypeAwareExpressionEvaluator {
754
755 private final Injector injector;
756 private final TypeAwareExpressionEvaluator evaluator;
757
758 WrapEvaluator(Injector injector, TypeAwareExpressionEvaluator evaluator) {
759 this.injector = injector;
760 this.evaluator = evaluator;
761 }
762
763 @Override
764 public Object evaluate(String expression) throws ExpressionEvaluationException {
765 return evaluate(expression, null);
766 }
767
768 @Override
769 public Object evaluate(String expression, Class<?> type) throws ExpressionEvaluationException {
770 Object value = evaluator.evaluate(expression, type);
771 if (value == null) {
772 String expr = stripTokens(expression);
773 if (expr != null) {
774 try {
775 value = injector.getInstance(Key.of(type, expr));
776 } catch (DIException e) {
777
778 }
779 }
780 }
781 return value;
782 }
783
784 private String stripTokens(String expr) {
785 if (expr.startsWith("${") && expr.endsWith("}")) {
786 return expr.substring(2, expr.length() - 1);
787 }
788 return null;
789 }
790
791 @Override
792 public File alignToBaseDirectory(File path) {
793 return evaluator.alignToBaseDirectory(path);
794 }
795 }
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827 }