Load Spring Boot component before Lombok instantation in unit test - java

I developed a kind of wrapper to make it work as a custom logger. I'm instantiating this class using #CustomLog Lombok annotation just to make it easier and cleaner. The tricky thing comes next: the idea behind this wrapper is to use a common logger (as org.slf4j.Logger) along with a custom monitor class that each time I call log.error(), the proper message gets logged in the terminal and the event is sent to my monitoring tool (Prometheus in this case).
To achieve this I did the following classes:
CustomLoggerFactory the factory called by Lombok to instantiate my custom logger.
public final class CustomLoggerFactory {
public static CustomLogger getLogger(String className) {
return new CustomLogger(className);
}
}
CustomLogger will receive the class name just to then call org.slf4j.LoggerFactory.
public class CustomLogger {
private org.slf4j.Logger logger;
private PrometheusMonitor prometheusMonitor;
private String className;
public CustomLogger(String className) {
this.logger = org.slf4j.LoggerFactory.getLogger(className);
this.className = className;
this.monitor = SpringContext.getBean(PrometheusMonitor.class);
}
}
PrometheusMonitor class is the one in charge of creating the metrics and that kind of things. The most important thing here is that it's being managed by Spring Boot.
#Component
public class PrometheusMonitor {
private MeterRegistry meterRegistry;
public PrometheusMonitor(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
}
As you may noticed, to access PrometheusMonitor from CustomLogger I need an additional class in order to get the Bean / access the context from a non Spring managed class. This is the SpringContext class which has an static method to get the bean by the class supplied.
#Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
public static <T extends Object> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
SpringContext.context = context;
}
}
So all this works just fine when running the application. I ensure to load SpringContext class before anything else, so once each CustomLogger gets instantiated it just works.
But the BIG issue comes here: this is not working while unit testing my app. I tried many things and I saw some solutions that may help me but that I'm trying to avoid (e.g. using PowerMockito). Lombok is processing #CustomLog annotation before any #Before method I add to my test class. Once getBean() method is called I get an exception cause context is null.
My guesses are that I could solve it if I can force the SpringContext to be loaded before Lombok does its magic, but I'm not sure that's even possible. Many thanks for taking your time to read this. Any more info I can provide just let me know.

NOTE: It sounds like your custom logging needs are better served by logging to slf4j as normal, and registering an additional handler with the slf4j framework so that slf4j will forward any logs to you (in addition to the other handlers, such as the one making the log files).
Lombok is processing #CustomLog
The generated log field is static. If an annotation is going to help at all, you'd need #BeforeClass, but that probably also isn't in time. Lombok's magic doesn't seem relevant here. Check out what delombok tells you lombok is doing: It's just.. a static field, being initialized on declaration.

Well I managed to solve this issue changing a little how the CustomLogger works. Meaning that instead of instantiating monitor field along with the logger, you can do it the first time you'll use it. E.g.:
public class CustomLogger {
private org.slf4j.Logger logger;
private Monitor monitor;
public CustomLogger(String className) {
this.logger = org.slf4j.LoggerFactory.getLogger(className);
}
public void info(String message) {
this.logger.info(message);
}
public void error(String message) {
this.logger.error(message);
if (this.monitor == null) {
this.monitor = SpringContext.getBean(PrometheusMonitor.class);
}
this.monitor.send(message);
}
}
But after all I decided to not follow this approach because I don't think it's the best one possible and worth it.

Related

Injecting a single Spring bean instance into a static variable of a utility class

I have this web application built with Spring and Vaadin, in which I wanted to do this, for the sake of convenience:
Create a utility class that wraps a Spring service, and allows the use of its static methods throughout the application, without having to worry about injecting this service everywhere, like so:
String configurationValue = ConfigurationUtil.getString("some.property.key");
If you work with Vaadin, you might see how convenient this is, because the whole presentation layer is written in Java and you can't always inject Spring services into your Vaadin components as these Vaadin components are not always Spring components themselves.
So this is my utility class:
public final class ConfigurationUtil {
// this is the spring service:
private static ConfigurationService configurationService;
public static void setConfigurationService(final ConfigurationService configurationService) {
ConfigurationUtil.configurationService = configurationService;
}
public static String getString(final String key) {
return configurationService.getString(key);
}
}
This is my service:
#Service("configurationService")
public class ConfigurationServiceImpl implements ConfigurationService, BeanFactoryAware {
private final FrameworkService frameworkService;
#Autowired
public ConfigurationServiceImpl(final FrameworkService frameworkService) throws IOException, ConfigurationException {
// this is where I set this service bean to the utility class
ConfigurationUtil.setConfigurationService(this);
this.frameworkService = frameworkService;
}
public String getString(String key) {
// code that retrieves a configuration value from our configuration files
}
}
My question here is: I'm a bit worried about this causing a bottleneck to access the configuration service, as multiple threads will be calling it, from multiple user sessions. Would this be a problem? Please explain why. Also, feel free to point out other problems with this solution.
I suggest to create a bean that implements ApplicationContextAware like this:
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext ac) {
context = ac;
}
public static String getString(final String key) {
ConfigurationService configurationService = context.getBean(ConfigurationService.class);
return configurationService.getString(key);
}
public static <T> T bean(Class<T> beanType) {
return context.getBean(beanType);
}
}
You can create a method like in the example to give static access to Spring Beans or what you requested to get a String from your ConfigurationService.
Btw. I use this a lot in Vaadin applications because I don't want to make every component a Spring Bean.

JpaRepository not autowiring in custom RichSinkFunction

I have created a custom Flink RichSinkFunction and attempted to autowire a JpaRepository within this custom class but I am constantly getting a NullPointerException.
If I autowire it in the constructor, I can see that the JpaRepo has been found - but when the invoke method is called, I receive a NullPointerException.
public interface MessageRepo extends JpaRepository<Message, Long> {
}
#Component
public class MessageSink extends RichSinkFunction<Message> {
private final transient MessageRepo messageRepo; //if i don't make this transient, i get the error message "The implementation of the RichSinkFunction is not serializable"
#Autowired
public MessageSink(MessageRepo messageRepo){
this.messageRepo = messageRepo;
messageRepo.save(new Message()); //no issues when i do this
}
#Override
public void invoke(Message message, Context context) {
// the message is not null
messageRepo.save(message); // NPE
}
Has anyone experienced this issue before? It looks like the MessageSink invoke method is being called in a separate thread which is why the messageRepo is always null?
Other parts of my code is able to use the MessageRepo apart from when I have my own custom sink.
I think the issue here is that flink needs to serialize the custom sink function before it distribute to its workers.
By marking the MessageRepo transit, meaning the field will be null when the worker node deserlize this function. Normally, you would initialise the transit dependency in the open function, which will be called after the object is deserialised.
I am not clearly sure about the reason, but I think spring boot gives priority to your service classes when it comes to injecting beans. I have faced a similar issue when I was trying to write a listener for my Entity class. This is how I solved it.
Create a component class which implements ApplicationContextAware interface and override setApplicationContext method. Have a static method in your class named getBean which will autowire on your first request. Sample code ---
#Component
public class SpringBeansUtil implements ApplicationContextAware {
private static ApplicationContext context;
#SuppressWarnings("static-access")
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext;
}
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
And then just get bean in your code ------->>
ClassName referenceName = (ClassName)SpringBeansUtil.getBean(ClassName.class);

Use Guice to create components to use with ThreadWeaver

The application I have been working on has been getting more and more complicated, and it's gotten to the point where I have been running into the same problems over and over again with concurrency. It no longer made any sense to solve the same problems and not have any regression tests.
That's when I found ThreadWeaver. It was really nice for some simple concurrency cases I cooked up, but I started to get frustrated when trying to do some more complicated cases with my production code. Specifically, when injecting components using Guice.
I've had a bit of a hard time understanding the implications of the way ThreadWeaver runs tests, and looked for any mention of Guice or DI in the wiki documents, but with no luck.
Is Guice compatible with ThreadWeaver?
Here is my test
#Test
public void concurrency_test() {
AnnotatedTestRunner runner = new AnnotatedTestRunner();
runner.runTests(OPYLWeaverImpl.class, OPYLSurrogateTranscodingService.class);
}
Here is my test implementation
public class OPYLWeaverImpl extends WeaverFixtureBase {
#Inject private TaskExecutor taskExecutor;
#Inject private Serializer serializer;
#Inject private CountingObjectFileMarshaller liveFileMarshaller;
#Inject private GraphModel graphModel;
#Inject private CountingModelUpdaterService updaterService;
#Inject private BabelCompiler babelCompiler;
#Inject private EventBus eventBus;
OPYLSurrogateTranscodingService service;
private Path testPath;
#ThreadedBefore
public void before() {
service = new OPYLSurrogateTranscodingService(eventBus, taskExecutor, serializer, liveFileMarshaller,
() -> new OPYLSurrogateTranscodingService.Importer(graphModel, babelCompiler, updaterService, eventBus),
() -> new OPYLSurrogateTranscodingService.Validator(eventBus, babelCompiler),
() -> new OPYLSurrogateTranscodingService.Exporter(graphModel, updaterService));
}
#ThreadedMain
public void mainThread() {
testPath = FilePathOf.OASIS.resolve("Samples/fake-powershell-unit-test.opyl");
service.applyToExistingGraphModel(testPath);
}
#ThreadedSecondary
public void secondaryThread() {
}
#ThreadedAfter
public void after() {
}
And the WeaverFixtureBase
public class WeaverFixtureBase {
#Inject protected CountingEventBus eventBus;
#Before public final void setupComponents() {
Injector injector = Guice.createInjector(new WeaverTestingEnvironmentModule(CommonSerializationBootstrapper.class));
injector.getMembersInjector((Class) this.getClass()).injectMembers(this);
}
private class WeaverTestingEnvironmentModule extends AbstractModule {
private final Class<? extends SerializationBootstrapper> serializationBootstrapper;
public WeaverTestingEnvironmentModule(Class<? extends SerializationBootstrapper> serializationConfiguration) {
serializationBootstrapper = serializationConfiguration;
}
#Override protected void configure() {
bind(TaskExecutor.class).to(FakeSerialTaskExecutor.class);
bind(SerializationBootstrapper.class).to(serializationBootstrapper);
bind(ModelUpdaterService.class).toInstance(new CountingModelUpdaterService());
bindFactory(StaticSerializationConfiguration.Factory.class);
CountingEventBus localEventBus = new CountingEventBus();
bind(Key.get(EventBus.class, Bindings.GlobalEventBus.class)).toInstance(localEventBus);
bind(Key.get(EventBus.class, Bindings.LocalEventBus.class)).toInstance(localEventBus);
bind(CountingEventBus.class).toInstance(localEventBus);
bind(EventBus.class).toInstance(localEventBus);
}
#Provides
#Singleton
public GraphModel getGraphModel(EventBus eventBus, Serializer serializer) {
return MockitoUtilities.createMockAsInterceptorTo(new GraphModel(eventBus, serializer));
}
}
But when the classloader loads OPYLWeaverImpl, none of the Guice stuff goes off and I get a big pile of nulls.
I feel like this is one of those "missing-something-really-simple" kind of scenarios. Sorry if it is!
The above comment is right. Thread-weaver is fully agnostic of JUnit. Thread weaver is its own runner that executes a test case respecting its own annotations. You must not use any JUnit-specific annotation within a Thread Weaver test.
Other than that, Thread Weaver does not need any compatibility for a specific framework. It manipulates Java byte code and loads that manipulated code using aeperate class loaders.
Finally, a Thread Weaver test without any secondary test does not make any sense. Thread weaver works by interleaving seperate execution paths. Without a second thread, Thread Weaver only steps through a single thread without adding any value.

Guice Singleton Static Injection Pattern

I'm new to Google Guice and understand Dependency Injection conceptually, but am running into issues trying to incorporate it into my application. My specific question is around Singleton objects. Here's an example:
First, my Module class, which binds a heavy Singleton Connection interface to its implementation.
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(Connection.class).to(MyConnection.class).asEagerSingleton();
}
}
Now, in my main method, I instantiate my application server and inject the Connection:
public class MyApplication {
#Inject
public MyApplication(Connection cxn) {
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new MyModule());
MyApplication app = injector.getInstance(MyApplication.class);
// Start application, add ShutdownHook, etc...
}
}
Everything good so far... Now, I have some DAO classes that leverage my Connection object, but are retrieved with static methods like so:
public class MyConfiguration {
private Config conf;
private Connection cxn; // Would like to have this injected
private MyConfiguration(Config conf) {
this.conf = conf;
}
public static MyConfiguration getConfig(String name) {
return new MyConfiguration(cxn.getConfig(name));
}
}
My first assumption was that I would simply add #Inject to cxn but this doesn't work because I am not getting the instance from Guice; it just gives me a NPE. The way I see it, I have 2 options for getting the Connection object:
Expose a getConnection() method in MyApplication essentially following the Service Locator Pattern
Add requestStaticInjection(MyConfiguration) to MyModule
I opted for #2, however the docs say:
This API is not recommended for general use
What is best practice for providing my Singleton to the classes that need it without having to go through Injector.getInstance each time? What am I missing?
You're thinking about dependency injection incorrectly. Dependency Injection and Service Locator are mirror-images of each other: with a service locator, you ask it for an object. With dependency injection, you don't go looking for dependencies, they're just handed to you.
Basically, "it's turtles all the way down"! Every dependency your class has should be injected. If MyApplication needs a MyConfiguration object, it should just accept a MyConfiguration object as a constructor parameter, and not worry about how it was constructed.
Now, this isn't to say that you can never use new manually -- but you should reserve that for value-type objects that don't have external dependencies. (And in those cases, I'd argue that you're often better off with a static factory method than a public constructor anyway, but that's beside the point.)
Now there are a couple of ways of doing this. One way is to shard MyConfiguration into lots of tiny pieces, so that instead of doing myConfiguration.getConfig("x") you would do #Inject #Configuration("x") String or something like that. Alternatively, you could make MyConfiguration itself injectable, and then provide accessor methods on it for the pieces. The right answer depends somewhat on the kind of data you're trying to model -- make the dependencies too fine-grained and your bindings may become hard to maintain (although there are ways to make that better); make the dependencies too coarse and you make it harder to test (for example: which is easier, providing just the "x" config that the class you're testing needs, or building the whole application's config?).
You can even do both:
/** Annotates a configuration value. */
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
public #interface Config {
String value();
}
/** Installs bindings for {#link MyConfiguration}. */
final class MyConfigurationModule extends AbstractModule {
#Override protected void configure() {}
#Provides
#Singleton
MyConfiguration provideMyConfiguration() {
// read MyConfiguration from disk or somewhere
}
#Provides
#Config("x")
String provideX(MyConfiguration config) {
return config.getConfig("x").getName();
}
}
// elsewhere:
/** The main application. */
final class MyApplication {
private final String xConfig;
#Inject MyApplication(#Config("x") String xConfig) {
this.xConfig = xConfig;
}
// ...
}
You can take a similar approach in unit tests:
/** Tests for {#link MyApplication}. */
#RunWith(JUnit4.class)
public final class MyApplicationTest {
// Note that we don't need to construct a full MyConfiguration object here
// since we're providing our own binding, not using MyConfigurationModule.
// Instead, we just bind the pieces that we need for this test.
#Bind #Config("x") String xConfig = "x-configuration-for-test";
#Before public void setUp() {
// See https://github.com/google/guice/wiki/BoundFields
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
}
#Inject MyApplication app;
#Test public void testMyApp() {
// test app here
}
}
Dependency injection also encourages another best practice which I highly recommend, which is to design your type system such that invalid states are not representable (to the maximal degree possible). If all the configuration MyApplication needs is passed in its constructor, it's impossible to ever have a MyApplication object that doesn't have a valid configuration. This allows you to "front-load" your class invariants, which makes it much easier to reason about the behavior of your objects.
Finally, a note about Injector.getInstance(). Ideally you use Injector exactly once in your program: immediately after it is constructed. That is, you should be able to do Guice.createInjector(...).getInstance(MyApplication.class).start() and never store a reference to the Injector anywhere. I tend to build applications using Guava's ServiceManager abstraction (see also this question), so the only thing I ever need to do is:
public static void main(String[] args) throws Exception {
Injector injector = Guice.createInjector(...);
ServiceManager manager = injector.getInstance(ServiceManager.class);
manager.startAsync().awaitHealthy();
}

Reflection + spring dependency injection

I'm trying to understand if I can combine reflection with spring dependency injection as the following:
public interface ClientCommand {
public void execute(...);
public static enum Command {
SomeCommand(SomeCommand.class);
private Class<? extends ClientCommand> clazz;
private Command(Class<? extends ClientCommand> clazz) {
this.clazz = clazz;
}
public Class<? extends ClientCommand> getClazz() {
return clazz;
}
public static ClientCommand getClientCommand(String name) {
Command command = Enum.valueOf(Command.class, name);
return command.getClazz().newInstance();
}
}
}
This will create an instance of a command class based on the name passed in getClientCommand.
This is an example of class extending ClientCommand:
public class LoginCommand implements ClientCommand {
#Autowired
private UserRepository userRepository;
public void setUserRepository(#Qualifier("userRepository")UserRepository userRepository) {
this.userRepository = userRepository;
}
public void execute(...) {
...
}
}
And the repository is something like:
#Repository("userRepository")
public class UserRepositoryImpl implements UserRepository {
....
}
When the LoginCommand.execute() method is executed, the UserRepository is null.
If I use the newInstance() to create the object, does spring care at all to inject the dependencies?
More than for practical use, is to understand if is theoretically possible to get this code working.
Thanks in advance
To answer this question:
If I use the newInstance() to create the object, does spring care at all to inject the dependencies?
I will answer with no, not by default. Spring will only inject dependencies on objects that Spring is in control of, and if you are using reflection to instantiate it, or the new operator, then you are the one in control, not Spring.
But, there is hope. You can use AspectJ to do bytecode weaving when the new operator is used, or even when Class.newInstance() is used.
Take a look at this Spring documentation for more on this approach.
Since you're creating the object on your own Spring will not do dependency injection on the object. It will also not add any AOP proxies for it if its configured to do that.
You can either use AspectJ to instrument your code by adding the logic necessary to do dependency injection on the instance. This is done completely transparently.
Or you can do it yourself by using AutowireCapableBeanFactory. It's a semi-internal interface that you can use and its intended for just this purpose. It has a set of methods that do various parts of creating and injecting, you'll probably need the createBean() method.
You can get an AutowireCapableBeanFactory by calling getAutowireCapableBeanFactory on your ApplicationContext.
In your case it would probably be a good idea to create a CommandFactory, make that implement ApplicationContextAware and have a method like createCommand() that calls createBean().

Categories