1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.impl;
20
21 import javax.inject.Named;
22 import javax.inject.Provider;
23
24 import java.io.BufferedReader;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.lang.annotation.Annotation;
29 import java.net.URL;
30 import java.nio.charset.StandardCharsets;
31 import java.util.ArrayList;
32 import java.util.Comparator;
33 import java.util.HashSet;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import java.util.function.Supplier;
39 import java.util.stream.Collectors;
40
41 import com.google.inject.AbstractModule;
42 import com.google.inject.binder.AnnotatedBindingBuilder;
43 import com.google.inject.name.Names;
44 import org.apache.maven.api.di.MojoExecutionScoped;
45 import org.apache.maven.api.di.SessionScoped;
46 import org.apache.maven.api.services.MavenException;
47 import org.apache.maven.di.Injector;
48 import org.apache.maven.di.Key;
49 import org.apache.maven.di.impl.Binding;
50 import org.apache.maven.di.impl.DIException;
51 import org.apache.maven.di.impl.InjectorImpl;
52 import org.apache.maven.execution.scope.internal.MojoExecutionScope;
53 import org.apache.maven.session.scope.internal.SessionScope;
54 import org.codehaus.plexus.PlexusContainer;
55 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
56
57 @Named
58 public class SisuDiBridgeModule extends AbstractModule {
59
60 InjectorImpl injector;
61 final Set<String> loaded = new HashSet<>();
62
63 @Override
64 protected void configure() {
65 Provider<PlexusContainer> containerProvider = getProvider(PlexusContainer.class);
66
67 injector = new InjectorImpl() {
68 @Override
69 public <Q> Supplier<Q> getCompiledBinding(Key<Q> key) {
70 Set<Binding<Q>> res = getBindings(key);
71 if (res != null && !res.isEmpty()) {
72 List<Binding<Q>> bindingList = new ArrayList<>(res);
73 Comparator<Binding<Q>> comparing = Comparator.comparing(Binding::getPriority);
74 bindingList.sort(comparing.reversed());
75 Binding<Q> binding = bindingList.get(0);
76 return compile(binding);
77 }
78 if (key.getRawType() == List.class) {
79 Set<Binding<Object>> res2 = getBindings(key.getTypeParameter(0));
80 Set<Binding<Object>> res3 = res2 != null ? new HashSet<>(res2) : new HashSet<>();
81 try {
82 List<Object> l = containerProvider
83 .get()
84 .lookupList(key.getTypeParameter(0).getRawType());
85 l.forEach(o -> res3.add(new Binding.BindingToInstance<>(o)));
86 } catch (Throwable e) {
87
88 e.printStackTrace();
89 }
90 List<Supplier<Object>> list =
91 res3.stream().map(this::compile).collect(Collectors.toList());
92
93 return () -> (Q) list(list);
94 }
95 if (key.getRawType() == Map.class) {
96 Key<?> k = key.getTypeParameter(0);
97 Key<Object> v = key.getTypeParameter(1);
98 if (k.getRawType() == String.class) {
99 Set<Binding<Object>> res2 = getBindings(v);
100 Set<Binding<Object>> res3 = res2 != null ? new HashSet<>(res2) : new HashSet<>();
101 Map<String, Supplier<Object>> map = res3.stream()
102 .filter(b -> b.getOriginalKey() == null
103 || b.getOriginalKey().getQualifier() == null
104 || b.getOriginalKey().getQualifier() instanceof String)
105 .collect(Collectors.toMap(
106 b -> (String)
107 (b.getOriginalKey() != null
108 ? b.getOriginalKey().getQualifier()
109 : null),
110 this::compile));
111
112 return () -> (Q) map(map);
113 }
114 }
115 try {
116 Q t = containerProvider.get().lookup(key.getRawType());
117 return compile(new Binding.BindingToInstance<>(t));
118 } catch (Throwable e) {
119
120 e.printStackTrace();
121 }
122 throw new DIException("No binding to construct an instance for key "
123 + key.getDisplayString() + ". Existing bindings:\n"
124 + getBoundKeys().stream()
125 .map(Key::toString)
126 .map(String::trim)
127 .sorted()
128 .distinct()
129 .collect(Collectors.joining("\n - ", " - ", "")));
130 }
131 };
132 injector.bindScope(SessionScoped.class, () -> {
133 try {
134 return containerProvider.get().lookup(SessionScope.class);
135 } catch (ComponentLookupException e) {
136 throw new RuntimeException(e);
137 }
138 });
139 injector.bindScope(MojoExecutionScoped.class, () -> {
140 try {
141 return containerProvider.get().lookup(MojoExecutionScope.class);
142 } catch (ComponentLookupException e) {
143 throw new RuntimeException(e);
144 }
145 });
146 injector.bindInstance(Injector.class, injector);
147 bind(Injector.class).toInstance(injector);
148 bind(SisuDiBridgeModule.class).toInstance(this);
149 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
150 if (classLoader == null) {
151 classLoader = getClass().getClassLoader();
152 }
153 loadFromClassLoader(classLoader);
154 injector.getBindings().keySet().stream()
155 .filter(k -> k.getQualifier() != null)
156 .sorted(Comparator.comparing(k -> k.getRawType().getName()))
157 .distinct()
158 .forEach(key -> {
159 Class<?> clazz = key.getRawType();
160 Class<Object> itf = (clazz.isInterface()
161 ? null
162 : (Class<Object>) (clazz.getInterfaces().length > 0 ? clazz.getInterfaces()[0] : clazz));
163 if (itf != null) {
164 AnnotatedBindingBuilder<Object> binder = bind(itf);
165 if (key.getQualifier() instanceof String s && !s.isEmpty()) {
166 binder.annotatedWith(Names.named(s));
167 } else if (key.getQualifier() instanceof Annotation a) {
168 binder.annotatedWith(a);
169 }
170 binder.toProvider(() -> injector.getInstance(clazz));
171 }
172 });
173 }
174
175 public void loadFromClassLoader(ClassLoader classLoader) {
176 try {
177 for (Iterator<URL> it = classLoader
178 .getResources("META-INF/maven/org.apache.maven.api.di.Inject")
179 .asIterator();
180 it.hasNext(); ) {
181 URL url = it.next();
182 if (loaded.add(url.toExternalForm())) {
183 List<String> lines;
184 try (InputStream is = url.openStream();
185 BufferedReader reader =
186 new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
187 lines = reader.lines()
188 .map(String::trim)
189 .filter(s -> !s.isEmpty() && !s.startsWith("#"))
190 .toList();
191 }
192 for (String className : lines) {
193 try {
194 Class<?> clazz = classLoader.loadClass(className);
195 injector.bindImplicit(clazz);
196 } catch (ClassNotFoundException e) {
197
198 e.printStackTrace();
199 }
200 }
201 }
202 }
203 } catch (IOException e) {
204 throw new MavenException(e);
205 }
206 }
207 }