Skip to content

Commit 3f53c91

Browse files
author
Simone Bordet
committed
Fixes COMETD-295 (Support injection of Oort and Seti instances in services).
The injection mechanism has been made more generic than only Oort and Seti, provided that the injectables are singletons.
1 parent caa4f66 commit 3f53c91

7 files changed

Lines changed: 190 additions & 106 deletions

File tree

cometd-java/cometd-java-annotations/src/main/java/org/cometd/java/annotation/AnnotationProcessor.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.List;
2626
import javax.annotation.PostConstruct;
2727
import javax.annotation.PreDestroy;
28+
import javax.inject.Inject;
2829

2930
import org.slf4j.Logger;
3031
import org.slf4j.LoggerFactory;
@@ -217,4 +218,70 @@ protected static boolean signaturesMatch(Class<?>[] candidate, Class<?>[] expect
217218

218219
return true;
219220
}
221+
222+
protected boolean processInjectables(Object bean, List<Object> injectables)
223+
{
224+
boolean result = false;
225+
for (Object injectable : injectables)
226+
result |= processInjectable(bean, injectable);
227+
return result;
228+
}
229+
230+
protected boolean processInjectable(Object bean, Object injectable)
231+
{
232+
boolean result = false;
233+
for (Class<?> c = bean.getClass(); c != Object.class; c = c.getSuperclass())
234+
{
235+
Field[] fields = c.getDeclaredFields();
236+
for (Field field : fields)
237+
{
238+
if (field.getAnnotation(Inject.class) != null)
239+
{
240+
if (field.getType().isAssignableFrom(injectable.getClass()))
241+
{
242+
Object value = getField(bean, field);
243+
if (value != null)
244+
{
245+
logger.debug("Avoid injection of field {} on bean {}, it's already injected with {}", new Object[]{field, bean, value});
246+
continue;
247+
}
248+
249+
setField(bean, field, injectable);
250+
result = true;
251+
logger.debug("Injected {} to field {} on bean {}", new Object[]{injectable, field, bean});
252+
}
253+
}
254+
}
255+
256+
Method[] methods = c.getDeclaredMethods();
257+
for (Method method : methods)
258+
{
259+
if (method.getAnnotation(Inject.class) != null)
260+
{
261+
Class<?>[] parameterTypes = method.getParameterTypes();
262+
if (parameterTypes.length == 1)
263+
{
264+
if (parameterTypes[0].isAssignableFrom(injectable.getClass()))
265+
{
266+
Method getter = findGetterMethod(c, method);
267+
if (getter != null)
268+
{
269+
Object value = invokeMethod(bean, getter);
270+
if (value != null)
271+
{
272+
logger.debug("Avoid injection of method {} on bean {}, it's already injected with {}", new Object[]{method, bean, value});
273+
continue;
274+
}
275+
}
276+
277+
invokeMethod(bean, method, injectable);
278+
result = true;
279+
logger.debug("Injected {} to method {} on bean {}", new Object[]{injectable, method, bean});
280+
}
281+
}
282+
}
283+
}
284+
}
285+
return result;
286+
}
220287
}

cometd-java/cometd-java-annotations/src/main/java/org/cometd/java/annotation/ClientAnnotationProcessor.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.lang.reflect.Field;
2020
import java.lang.reflect.InvocationTargetException;
2121
import java.lang.reflect.Method;
22+
import java.util.Arrays;
2223
import java.util.List;
2324
import java.util.concurrent.ConcurrentHashMap;
2425
import java.util.concurrent.ConcurrentMap;
@@ -61,12 +62,18 @@ public class ClientAnnotationProcessor extends AnnotationProcessor
6162
private final ConcurrentMap<Object, List<ListenerCallback>> listeners = new ConcurrentHashMap<Object, List<ListenerCallback>>();
6263
private final ConcurrentMap<Object, List<SubscriptionCallback>> subscribers = new ConcurrentHashMap<Object, List<SubscriptionCallback>>();
6364
private final ClientSession clientSession;
65+
private final Object[] injectables;
6466

6567
public ClientAnnotationProcessor(ClientSession clientSession)
6668
{
67-
this.clientSession = clientSession;
69+
this(clientSession, new Object[0]);
6870
}
6971

72+
public ClientAnnotationProcessor(ClientSession clientSession, Object... injectables)
73+
{
74+
this.clientSession = clientSession;
75+
this.injectables = injectables;
76+
}
7077
/**
7178
* Processes dependencies annotated with {@link Session}, and callbacks
7279
* annotated with {@link Listener} and {@link Subscription}.
@@ -155,13 +162,15 @@ private boolean processDependencies(Object bean)
155162
if (serviceAnnotation == null)
156163
return false;
157164

158-
return processSession(bean, clientSession);
165+
boolean result = processInjectables(bean, Arrays.asList(injectables));
166+
result |= processSession(bean, clientSession);
167+
return result;
159168
}
160169

161170
private boolean processSession(Object bean, ClientSession clientSession)
162171
{
163172
boolean result = false;
164-
for (Class<?> c = bean.getClass(); c != null; c = c.getSuperclass())
173+
for (Class<?> c = bean.getClass(); c != Object.class; c = c.getSuperclass())
165174
{
166175
Field[] fields = c.getDeclaredFields();
167176
for (Field field : fields)
@@ -201,7 +210,7 @@ private boolean processSession(Object bean, ClientSession clientSession)
201210
private boolean processListener(Object bean)
202211
{
203212
boolean result = false;
204-
for (Class<?> c = bean.getClass(); c != null; c = c.getSuperclass())
213+
for (Class<?> c = bean.getClass(); c != Object.class; c = c.getSuperclass())
205214
{
206215
Method[] methods = c.getDeclaredMethods();
207216
for (Method method : methods)
@@ -255,7 +264,7 @@ private boolean deprocessListener(Object bean)
255264
private boolean processSubscription(Object bean)
256265
{
257266
boolean result = false;
258-
for (Class<?> c = bean.getClass(); c != null; c = c.getSuperclass())
267+
for (Class<?> c = bean.getClass(); c != Object.class; c = c.getSuperclass())
259268
{
260269
Method[] methods = c.getDeclaredMethods();
261270
for (Method method : methods)

cometd-java/cometd-java-annotations/src/main/java/org/cometd/java/annotation/ServerAnnotationProcessor.java

Lines changed: 15 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.lang.reflect.Field;
2020
import java.lang.reflect.InvocationTargetException;
2121
import java.lang.reflect.Method;
22+
import java.util.ArrayList;
23+
import java.util.Arrays;
2224
import java.util.List;
2325
import java.util.concurrent.ConcurrentHashMap;
2426
import java.util.concurrent.ConcurrentMap;
@@ -79,10 +81,17 @@ public class ServerAnnotationProcessor extends AnnotationProcessor
7981
private final ConcurrentMap<Object, List<ListenerCallback>> listeners = new ConcurrentHashMap<Object, List<ListenerCallback>>();
8082
private final ConcurrentMap<Object, List<SubscriptionCallback>> subscribers = new ConcurrentHashMap<Object, List<SubscriptionCallback>>();
8183
private final BayeuxServer bayeuxServer;
84+
private final Object[] injectables;
8285

8386
public ServerAnnotationProcessor(BayeuxServer bayeuxServer)
87+
{
88+
this(bayeuxServer, new Object[0]);
89+
}
90+
91+
public ServerAnnotationProcessor(BayeuxServer bayeuxServer, Object... injectables)
8492
{
8593
this.bayeuxServer = bayeuxServer;
94+
this.injectables = injectables;
8695
}
8796

8897
/**
@@ -197,7 +206,9 @@ public boolean processDependencies(Object bean)
197206
if (serviceAnnotation == null)
198207
return false;
199208

200-
boolean result = processBayeux(bean);
209+
List<Object> injectables = new ArrayList<Object>(Arrays.asList(this.injectables));
210+
injectables.add(0, bayeuxServer);
211+
boolean result = processInjectables(bean, injectables);
201212
LocalSession session = findOrCreateLocalSession(bean, serviceAnnotation.value());
202213
result |= processSession(bean, session);
203214
return result;
@@ -302,70 +313,12 @@ private LocalSession findOrCreateLocalSession(Object bean, String name)
302313
return session;
303314
}
304315

305-
private boolean processBayeux(Object bean)
306-
{
307-
boolean result = false;
308-
for (Class<?> c = bean.getClass(); c != null; c = c.getSuperclass())
309-
{
310-
Field[] fields = c.getDeclaredFields();
311-
for (Field field : fields)
312-
{
313-
if (field.getAnnotation(Inject.class) != null)
314-
{
315-
if (field.getType().isAssignableFrom(bayeuxServer.getClass()))
316-
{
317-
Object value = getField(bean, field);
318-
if (value != null)
319-
{
320-
logger.debug("Avoid injection of field {} on bean {}, it's already injected with {}", new Object[]{field, bean, value});
321-
continue;
322-
}
323-
324-
setField(bean, field, bayeuxServer);
325-
result = true;
326-
logger.debug("Injected {} to field {} on bean {}", new Object[]{bayeuxServer, field, bean});
327-
}
328-
}
329-
}
330-
331-
Method[] methods = c.getDeclaredMethods();
332-
for (Method method : methods)
333-
{
334-
if (method.getAnnotation(Inject.class) != null)
335-
{
336-
Class<?>[] parameterTypes = method.getParameterTypes();
337-
if (parameterTypes.length == 1)
338-
{
339-
if (parameterTypes[0].isAssignableFrom(bayeuxServer.getClass()))
340-
{
341-
Method getter = findGetterMethod(c, method);
342-
if (getter != null)
343-
{
344-
Object value = invokeMethod(bean, getter);
345-
if (value != null)
346-
{
347-
logger.debug("Avoid injection of method {} on bean {}, it's already injected with {}", new Object[]{method, bean, value});
348-
continue;
349-
}
350-
}
351-
352-
invokeMethod(bean, method, bayeuxServer);
353-
result = true;
354-
logger.debug("Injected {} to method {} on bean {}", new Object[]{bayeuxServer, method, bean});
355-
}
356-
}
357-
}
358-
}
359-
}
360-
return result;
361-
}
362-
363316
private boolean processSession(Object bean, LocalSession localSession)
364317
{
365318
ServerSession serverSession = localSession.getServerSession();
366319

367320
boolean result = false;
368-
for (Class<?> c = bean.getClass(); c != null; c = c.getSuperclass())
321+
for (Class<?> c = bean.getClass(); c != Object.class; c = c.getSuperclass())
369322
{
370323
Field[] fields = c.getDeclaredFields();
371324
for (Field field : fields)
@@ -417,7 +370,7 @@ else if (parameterTypes[0].isAssignableFrom(serverSession.getClass()))
417370
private boolean processListener(Object bean, LocalSession localSession)
418371
{
419372
boolean result = false;
420-
for (Class<?> c = bean.getClass(); c != null; c = c.getSuperclass())
373+
for (Class<?> c = bean.getClass(); c != Object.class; c = c.getSuperclass())
421374
{
422375
Method[] methods = c.getDeclaredMethods();
423376
for (Method method : methods)
@@ -472,7 +425,7 @@ private boolean deprocessListener(Object bean)
472425
private boolean processSubscription(Object bean, LocalSession localSession)
473426
{
474427
boolean result = false;
475-
for (Class<?> c = bean.getClass(); c != null; c = c.getSuperclass())
428+
for (Class<?> c = bean.getClass(); c != Object.class; c = c.getSuperclass())
476429
{
477430
Method[] methods = c.getDeclaredMethods();
478431
for (Method method : methods)

cometd-java/cometd-java-annotations/src/test/java/org/cometd/java/annotation/ClientAnnotationProcessorTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.concurrent.atomic.AtomicReference;
2323
import javax.annotation.PostConstruct;
2424
import javax.annotation.PreDestroy;
25+
import javax.inject.Inject;
2526

2627
import org.cometd.bayeux.Channel;
2728
import org.cometd.bayeux.Message;
@@ -45,6 +46,7 @@
4546
import static org.junit.Assert.assertFalse;
4647
import static org.junit.Assert.assertNotNull;
4748
import static org.junit.Assert.assertNull;
49+
import static org.junit.Assert.assertSame;
4850
import static org.junit.Assert.assertTrue;
4951

5052
public class ClientAnnotationProcessorTest
@@ -352,4 +354,31 @@ public void onMessage(ClientSessionChannel channel, Message message)
352354
bayeuxClient.getChannel("/foo").publish(new HashMap());
353355
assertFalse(messageLatch.get().await(1000, TimeUnit.MILLISECONDS));
354356
}
357+
358+
@Test
359+
public void testInjectables() throws Exception
360+
{
361+
class I
362+
{
363+
}
364+
365+
class II extends I
366+
{
367+
}
368+
369+
@Service
370+
class S
371+
{
372+
@Inject
373+
private I i;
374+
}
375+
376+
I i = new II();
377+
S s = new S();
378+
processor = new ClientAnnotationProcessor(bayeuxClient, i);
379+
boolean processed = processor.process(s);
380+
assertTrue(processed);
381+
382+
assertSame(i, s.i);
383+
}
355384
}

0 commit comments

Comments
 (0)