Puzzling first attempt...

113 views
Skip to first unread message

David Harrigan

unread,
Feb 18, 2014, 10:00:10 AM2/18/14
to reactor-...@googlegroups.com
Hi,

Java 1.7u51
Reactor 1.1.0-BUILD-SNAPSHOT
Spring 4.0.1

I have Reactor configured thus:

@Configuration
@EnableReactor
@ComponentScan
public class PlatformConfiguration {

    @Bean
    public Reactor reactor(final Environment environment) {
        return Reactors.reactor(environment, RING_BUFFER);
    }

}

I have a controller that I'm playing around with, i.e.,

@RestController
public class PingController {

    public Callable<Long> ping() {
        return new Callable<Long>() {
            @Override
            public Long call() throws Exception {
                reactor.notify("do.me.a.ping", Event.wrap(new PingEvent("w00t")));
                return 1L;
            }
         }
      }
}

Then, in my Service, I have:

@Service
public class PingServiceImpl implements PingService {

    @Selector("do.me.a.ping")
    public void count2(final PingEvent pingEvent) {
        System.out.println(pingEvent.getMessage());
    }

}

When I spin this puppy up, Spring throws an exception:

2014-02-18 14:38:10.215:WARN:oejw.WebAppContext:main: Failed startup of context o.e.j.w.WebAppContext@10a74ad1{/,file:/home/foo/foo/jetty-distribution-9.1.2.v20140210/webapps/ROOT/,STARTING}{/ROOT}
org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Field or property 'reactor' cannot be found on object of type 'foo.bar.PingControlerImp$$EnhancerByCGLIB$$a577cfc5'
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:217)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:85)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:78)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:102)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:94)
at reactor.spring.factory.config.ConsumerBeanAutoConfiguration.expression(ConsumerBeanAutoConfiguration.java:165)
at reactor.spring.factory.config.ConsumerBeanAutoConfiguration.fetchObservable(ConsumerBeanAutoConfiguration.java:169)
at reactor.spring.factory.config.ConsumerBeanAutoConfiguration.wireBean(ConsumerBeanAutoConfiguration.java:133)
at reactor.spring.factory.config.ConsumerBeanAutoConfiguration.onApplicationEvent(ConsumerBeanAutoConfiguration.java:108)
at reactor.spring.factory.config.ConsumerBeanAutoConfiguration.onApplicationEvent(ConsumerBeanAutoConfiguration.java:46)

I wonder if anyone would have an idea about what I've failed to do?

Thank you.

-=david=-

Stephane Maldini

unread,
Feb 18, 2014, 10:10:11 AM2/18/14
to David Harrigan, reactor-framework
Mmmh seems it does need the property Reactor to be locally injected. 

Can you try using the following field and re-run your test:
@AutoWired Reactor reactor


--
You received this message because you are subscribed to the Google Groups "reactor-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to reactor-framew...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Stephane Maldini | Solutions Architect, EMEA | Pivotal 
goPivotal.com | T: @smaldini

Jon Brisbin

unread,
Feb 18, 2014, 10:14:18 AM2/18/14
to Stephane Maldini, David Harrigan, reactor-framework
I suspect that's the problem. It's trying to figure out what Reactor you want to connect to but without one injected locally, it doesn't know.

You can also reference reactor="@reactorBeanName" in the annotation if you'd rather not inject the Reactor into your @Service.


Thanks!

Jon Brisbin | Reactor Project Lead

Stephane Maldini

unread,
Feb 18, 2014, 10:21:00 AM2/18/14
to Jon Brisbin, David Harrigan, reactor-framework
@AutoWired on a field require setter injection, just checking with you as it is easy to miss, have you got setReactor(Reactor reactor) ?
If you don't like setter injection you can use Constructor one. 

Jon Brisbin

unread,
Feb 18, 2014, 10:22:40 AM2/18/14
to Stephane Maldini, David Harrigan, reactor-framework
FWIW- I generally prefer constructor injection and making injected fields final. But it's mostly a personal preference.


Thanks!

Jon Brisbin | Reactor Project Lead

David Harrigan

unread,
Feb 18, 2014, 10:32:31 AM2/18/14
to Jon Brisbin, Stephane Maldini, reactor-framework
Hi Everyone

Firstly, thank you to all for your kind replies.

I have got it to work following your suggestions. This is what I did

(I personally perfer setter injection....:-))

In PingServiceImpl:

private Reactor reactor;

@Resource
public void setReactor(final Reactor reactor) {
   this.reactor = reactor;
}

However, when I first did this:

@Selector(value = "request.order.count.event", reactor = "reactor")

It failed,

Then I did this:

@Selector(value = "request.order.count.event", reactor = "@reactor")

and it worked!

I think the default value in the annotation has the wrong default?. surely it should have "String reactor() default "@reactor"; and not just "reactor"?

-=david=- 
--
I prefer encrypted and signed messages. KeyID: B20A22F9
Fingerprint: 110A F423 3647 54E2 880F ADAD 1C52 85BF B20A 22F9

"It is not usually until you've built and used a version of the program that you understand the issues well enough to get the design right." - Rob Pike, Brian Kernighan.

No trees were harmed in the sending of this message, however, a number of electrons were inconvenienced.

Jon Brisbin

unread,
Feb 18, 2014, 10:39:04 AM2/18/14
to David Harrigan, Stephane Maldini, reactor-framework

On Tuesday, February 18, 2014 at 9:32 AM, David Harrigan wrote:

However, when I first did this:

@Selector(value = "request.order.count.event", reactor = "reactor")

It failed,

This should mean, in SpEL terms "a property on the bean named 'reactor'". It's odd that it's not finding it. Is there a getter as well as a setter?
 

Then I did this:

@Selector(value = "request.order.count.event", reactor = "@reactor")

and it worked!
 
This means, in SpEL terms "a bean in the ApplicationContext called 'reactor'". Which may or may not be what you want, depending on what your service is doing.


I think the default value in the annotation has the wrong default?. surely it should have "String reactor() default "@reactor"; and not just "reactor"?

The safest default is to assume a property on the bean with the name "reactor" to make sure you don't "accidentally" pick up any one of a number of other Reactors that might be defined in the ApplicationContext.

David Harrigan

unread,
Feb 18, 2014, 10:43:43 AM2/18/14
to Jon Brisbin, Stephane Maldini, reactor-framework
Hi,

I only have a setter on my service which takes the Reactor (configured as a @Bean in my Configuration class), as a @Resource and in the class itself it's just a private Reactor reactor. In 99.999% of my application, I use this paradigm, I setter inject with a private field on the class. I agree, surely the Service should be introspected, a field called Reactor found and used by the @Selector?

-=david=-

Jon Brisbin

unread,
Feb 18, 2014, 10:47:18 AM2/18/14
to David Harrigan, Stephane Maldini, reactor-framework
On Tuesday, February 18, 2014 at 9:43 AM, David Harrigan wrote:
Hi,

I only have a setter on my service which takes the Reactor (configured as a @Bean in my Configuration class), as a @Resource and in the class itself it's just a private Reactor reactor. In 99.999% of my application, I use this paradigm, I setter inject with a private field on the class. I agree, surely the Service should be introspected, a field called Reactor found and used by the @Selector?

I seem to remember having issues with the way SpEL wants to interact with beans. I think this is one area I'm not a big fan of, but I'm pretty sure you need a public getter for SpEL to find the property (unless you change the way SpEL finds properties…I'm not sure there's an easy knob for that but I'll check).

David Harrigan

unread,
Feb 18, 2014, 10:55:36 AM2/18/14
to Jon Brisbin, Stephane Maldini, reactor-framework
Hi,

Yes, urgh :-( 

If I put a 

public Reactor getReactor() {
return reactor;
}

on my service, and change the @Selector just to have the key (with no reactor = "@reactor"), then it boots.

-=david=-

David Harrigan

unread,
Feb 18, 2014, 10:57:19 AM2/18/14
to Jon Brisbin, Stephane Maldini, reactor-framework
Urrgh

Bizarrely,

If I *remove* the setter and getter from the service and simply do @Autowired private Reactor reactor, then it _fails_ to boot.

-=david=-

Jon Brisbin

unread,
Feb 18, 2014, 11:03:44 AM2/18/14
to David Harrigan, Stephane Maldini, reactor-framework
What if you inject the Reactor into a final private field and provide only a getter?


Thanks!

Jon Brisbin | Reactor Project Lead

David Harrigan

unread,
Feb 18, 2014, 11:09:18 AM2/18/14
to Jon Brisbin, Stephane Maldini, reactor-framework
Hi,

That works. 

I guess it's all a little confusing. I was following the example as laid out here http://goo.gl/O0hJTP. There are no public getter methods (on the AnnotatedHandler) so nothing to suggest that I would need one. 

It feels like a problem with spEL? It's a bit ugly to expose a getter for a field that Spring is injecting, but then spEL can't find.

To recap:

@Autowired private Reactor reactor works only if there is a corresponding getReactor() on the class.

Using @Resource setReactor only works if there is a corresponding getReactor() on the class.

@Autowired on a field by itself or @Resource on a setter by itself do not work without a getReactor() on the class.

-=david=-



You received this message because you are subscribed to a topic in the Google Groups "reactor-framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/reactor-framework/S5iGSQ7Ze7Q/unsubscribe.
To unsubscribe from this group and all its topics, send an email to reactor-framew...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
Reply all
Reply to author
Forward
0 new messages