I'm trying to use cometd as a servlet to dropwizard but BayeuxServer doesn't seem to get injected in my service. I'm adding my two servlets as so (note, I'm not using web.xml so I'm defining the params myself):
cometdConfig.put("services", MyService.class.getCanonicalName());
System.out.print("OrderService name: " + MyService.class.getCanonicalName());
environment.addServlet(AnnotationCometdServlet.class, "/cometd/*").addInitParams(cometdConfig).setInitOrder(1);
environment.addServlet(new MyServiceServlet(), "/orders/*").setInitOrder(2);
And my service (this is where my code fails):
public class MyService
implements MyWatcher.Listener
{
#Inject
private BayeuxServer bayeuxServer;
#Session
private LocalSession sender;
private final String _channelName;
private ServerChannel _channel = null;
public OrderService() {
_channelName = "/cometd/";
initChannel();
}
private void initChannel() {
// I get an NPE here
bayeuxServer.createIfAbsent(_channelName, new ConfigurableServerChannel.Initializer() {
#Override
public void configureChannel(ConfigurableServerChannel channel) {
// ...
}
});
_channel = bayeuxServer.getChannel(_channelName);
}
}
I have also tried creating my own instance of the BayeuxServer but then that leads to a separate NPE in BayeuxServerImpl.freeze();
Anyone know how to properly use cometd with dropwizard?
In order to inject the BayeuxServer instance, CometD must have the instance of the service to inject to, in this case an instance of your class MyService.
Unfortunately, from the constructor (which I think you misnamed above, calling it OrderService) you are calling the initChannel() method, which tries to use the BayeuxServer field which is not yet injected because the constructor is still executing.
The solution is to defer your channel initialization to a different method annotated with #PostConstruct:
public class MyService
{
#Inject
private BayeuxServer bayeuxServer;
#Session
private LocalSession sender;
private final String _channelName;
private ServerChannel _channel;
public MyService()
{
_channelName = "/cometd/";
}
#PostConstruct
private void initChannel()
{
_channel = bayeuxServer.createChannelIfAbsent(_channelName).getReference();
}
}
The CometD API used is from CometD 2.7.0, which I recommend to use if you are on older CometD versions.
Related
I'm interested in using HK2 or Guice for a dependency injection framework.
I know of #Named, #Qualifier, and custom annotations etc. But these are all compile-time.
I am looking for a facility to dynamically determine the desired concrete type based on runtime context and inject the correct implementation.
Is there something like that in HK2 or Guice or a recommended way of achieving this?
For example:
// I would want to turn this...
public final class Handler
{
private final Session session;
#Inject
public Handler(#Named("Database") final Session session)
{
this.session = session;
}
...
}
// into something like this...
public final class Handler
{
private final Session session;
#Inject
public Handler(final Session session)
{
this.session = session;
}
}
// where "session" is injected based on some previous context value ("Database")
// or something to that effect.
I ended up using a feature in HK2 called Operations (link to docs). It allows a user of HK2 to define custom scopes and manage them as "operations". You can find a more detailed example of how to use the feature on HK2's github project: operations example.
This is a simplified example of how I ended up using this feature to inject things based on context or in this case "scope".
Here is some almost-working pseudo-code to demonstrate my usage:
// Create the custom scope annotation.
#Scope
#Proxiable(proxyForSameScope = false)
#Documented
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
public #interface BatchScope
{
public static final BatchScope INSTANCE = new BatchScopeEnvoy();
}
final class BatchScopeEnvoy extends AnnotationLiteral<BatchScope> implements BatchScope
{
private static final long serialVersionUID = 938233179310254573L;
}
// Create a context used by the HK2 operation feature.
#Singleton
public final class BatchScopeContext extends OperationContext<BatchScope>
{
#Override
public Class<? extends Annotation> getScope()
{
return BatchScope.class;
}
}
// Create a class that holds your custom scope data/context.
public final class BatchScopeRuntime
{
// ... Arbitrary runtime data here ...
public SomeData getData()
{
return this.data;
}
}
// Create a factory that serves up something you want to inject from a custom scope.
#Singleton
public final class DataFactory implements Factory<SomeData>
{
private final OperationManager operations;
#Inject
public BatchInfoFactory(final OperationManager operations)
{
Sentinel.assertIsNotNull(operations);
this.operations = operations;
}
// The #BatchScope on the provide() method indicates that objects returned
// from this factory are in the "BatchScope".
#Override
#BatchScope
public IBatchInfo provide()
{
final OperationHandle handle = this.operations.getCurrentOperation(BatchScope.INSTANCE);
final BatchScopeRuntime runtime = (BatchScopeRuntime)handle.getOperationData();
return runtime.getData();
}
#Override
public void dispose(final IBatchInfo instance)
{
// Do nothing.
}
}
// Setup the injector.
public static ServiceLocator createInjector(final String name)
{
final ServiceLocator injector = ServiceLocatorFactory.getInstance().create(name);
ServiceLocatorUtilities.bind(
injector,
new AbstractBinder()
{
#Override
protected void configure()
{
// This creates a "Singleton" factory that provides
// "SomeData" instances at "BatchScope".
bindFactory(DataFactory.class, Singleton.class)
.to(SomeData.class)
.in(BatchScope.class);
}
}
return injector;
}
// Create a class that needs something in the custom scope.
public final class Foo
{
#Inject
public Foo(final SomeData data)
{
System.out.printf("I got: %s%n", data);
}
}
// Usage: how to manage the scopes using the operations feature.
final SomeData data = ... // get some data
final BatchScopeRuntime runtime = new BatchScopeRuntime(data); // Setup the runtime information.
// Create an operation handle for the custom scope and associate the custom data with it.
final ServiceLocator injector = createInjector("test");
ServiceLocatorUtilities.addClasses(injector, BatchScopeContext.class, Foo.class);
final OperationManager operations = injector.getService(OperationManager.class);
final OperationHandle<BatchScope> batchScope = operations.createAndStartOperation(BatchScope.INSTANCE);
// Operation/scope is now associated with the current thread.
batchScope.setOperationData(runtime);
// Foo will now be injected with: "data" from above.
final Foo foo = injector.getService(Foo.class);
// Do some work...
// Close the operation (make it go out of scope) on the current thread.
batchScope.closeOperation();
I define an object as with scope "thread".
In some place in the code the instance is obtained with #Autowired and in other place with context getBean(), when comparing the objects, they are different.
Since the object is "thread" scoped I was expecting the same instance of the object to be returned.
Following is the code, first I define a custom scope
#Configuration
public class ThreadScopeRegisteringBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerScope("thread", new SimpleThreadScope());
}
}
A test object is defined as:
#Component
#Scope("thread")
public class ThreadScopeObject implements InitializingBean {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadScopeObject.class);
private String field1;
public String getField1() {
return field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
#Override
public void afterPropertiesSet() throws Exception {
LOGGER.info("****************** new object - " + this);
}
}
Also a service is defined as:
#Service
public class ThreadScopeService {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadScopeService.class);
#Autowired
private ThreadScopeObject threadScopeObject;
public void showObject() {
LOGGER.info ("ShowObject: " + threadScopeObject);
}
}
And finally a Async method is defined [RunnableService.java]:
#Async
public CompletableFuture<Map> objectInstanceTest() {
ThreadScopeObject o = ApplicationContextHolder.getContext().getBean(ThreadScopeObject.class);
LOGGER.info ("Thread object: " + o);
service.showObject();
return CompletableFuture.completedFuture(new HashMap<>());
}
When running the application I get the following log:
19:15:27.094 [mcd-async-1] INFO com.mono.threadSample.ThreadScopeObject - ****************** new object - com.mono.threadSample.ThreadScopeObject#69c8f2bb
19:15:27.094 [mcd-async-1] INFO com.mono.threadSample.RunnableService - Thread object: com.mono.threadSample.ThreadScopeObject#69c8f2bb
19:15:27.094 [mcd-async-1] INFO com.mono.threadSample.ThreadScopeService - ShowObject: com.mono.threadSample.ThreadScopeObject#fd0e5b6
I would like to know the reason why an object "thread" scoped is instantiated twice in the same thread.
Code: https://github.com/saavedrah/spring-threadSample
Thank you.
The ThreadScopeService is a singleton by default, so when it is constructed by spring it will get a ThreadScopeObject from the thread that created it and it won't be updated afterwards. There are two ways to solve this:
inject a Provider<ThreadScopeObject> or ObjectFactory<ThreadScopeObject> into ThreadScopeService and call their get methods to retrieve the scoped object when needed.
annotate the ThreadScopeObject with #Scope("thread", proxyMode = ScopedProxyMode.TARGET_CLASS). This will make spring create a proxy around your object, which will delegate all calls to the correctly scoped instance.
I have a Rest Controller in which I initialise a service like this :
class Config {
#Value(${"number.of.books"})
private final static String numberOfBooks;
}
class MyController {
private final Service myService = new ServiceImplementation(Config.numberOfBooks)
public ResponseEntity methodA() { ... }
}
The numberOfBooks field has a initialisation value but when it's passed in the ServiceImplementation constructor it comes null.
I'm thinking I'm missing something obvious over here.
What is the mistake and which would be the best practice to inject a value from a property file into a constructor?
I recommend you to directly inject numberOfBooks in your ServiceImplementation, as follows:
public class ServiceImplementation implements Service {
#Value("${number.of.books}")
private String numberOfBooks;
}
Otherwise use setter injection for static variables, as follows:
#Component
class Config {
public static String numberOfBooks;
#Value("${number.of.books}")
public void setNumberOfBooks(String numberOfBooks) {
numberOfBooks = numberOfBooks;
}
}
After studying a little I've found out that the dependency injection happens after the constructor has been called. This being said the approach used was to use Autowired on my services constructor.
class ServiceImplementation implements Service {
private final String numberOfBooks;
#Autowired
private ServiceImplementation(Config config) {
this.numberOfBooks = config.getNumberOfBooks();
}
}
In this way Spring creates the dependency tree and makes sure that Config is not null when injected.
I have an object reads configuration properties like this:
#ApplicationScoped
public class Configuration {
#Inject
#Config(value = "endpoint.base", defaultValue = "http://localhost:52885/consumers")
private String base;
public String getBase() { return base; }
}
this object is injected to a service object like this:
public class LoyaltyService {
final Sender sender;
final Configuration config;
#Inject
public LoyaltyService(Sender sender, Configuration config) {
this.sender = sender;
this.config = config;
}
}
I am now testing this service object with Mockito. I want to mock the Sender object, but I don't want to mock the configuration, or at least I just want to use the default value defined inside the object.
How can I do that in a Test object?
For example, I tried the following:
public class LoyaltyServiceTest {
#Mock
private Sender sender;
#Inject
private Configuration config;
private LoyaltyService target;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
when (sender.post(anyString(), anyString())).thenReturn("Post Success");
target =new LoyaltyService(sender, config);
}
}
It doesn't seem CDI will register the Config object at all. How does this work? Thanks!
It doesn't seem CDI will register the Config object at all.
The CDI beans are not initialised when running the test, only the mocked objects are.
MockitoAnnotations.initMocks only initializes
objects annotated with Mockito annotations for given testClass: #Mock, #Spy, #Captor, #InjectMocks.
You need to use a CDI test framework like cdi-unit or Pax Exam in your test class to create the non-mocked beans for you.
In our company we work a lot with small Java applications as service in Windows. To be able to get status reports from these applications we use Jersey to output some JSON data.
To get the needed application data we currently setup the application as a singleton. From the resource handler in Jersey we can access the object via it's static getInstance method.
Now we are upgrading the complete application landscape and have made some changes to our applications. One of the changes is that the applications are no longer singletons. Is there any other way of accessing the application object without it being singleton and without the handler being an inner class?
Here is a simplified version of the code:
public class Main {
protected int data; // a property which has to be accessible by
// the jersey handler
protected Closeable server;
protected ResourceConfig resourceConfig;
public Main() {
// set the jersey handle
resourceConfig = new DefaultResourceConfig(JerseyHandler.class);
// start the jersey server
server = SimpleServerFactory.create("http://0.0.0.0:" + port, resourceConfig);
}
public int getData() {
return data;
}
}
#Path("/")
public class JerseyHandler {
#Path("status")
#GET
public Response status() {
// how to access Main's getData() method from here without
// anything being a singleton or an inner class???
int data = ????;
Response.ok().entity(data).build();
}
}
You should inject Main as dependency with Dependency Injection mechanism that is supported by Jersey. I use Jersey 2.12 and Google Guice 3.0 for the same purpose.
Example:
#Singleton
#Path("language")
#Produces(MediaType.APPLICATION_JSON)
public class LanguageResource {
private final LanguageService langService;
#Inject
public LanguageResource(LanguageService dateService) {
langService = dateService;
}
}
To configure the listener with custom Guice module:
ServletContextHandler handler = new ServletContextHandler();
handler.setServer(server);
handler.addEventListener(new ServletGuiceConfig());
Your Guice config could look like this:
public class ServletGuiceConfig extends GuiceServletContextListener {
protected static Injector injector;
#Override
protected Injector getInjector() {
injector = Guice.createInjector(new ServiceConfig(), new ServletModule() {
#Override
protected void configureServlets() {
bind(LanguageService.class).to(LanguageServiceImpl.class);
}
});
return injector;
}
}