how to inject a dependency in a java enum? - java

I am trying to inject a bean into an enum but i keep getting null pointer exception when call to someMethod is made.
The answer mentioned in this Inject bean into enum worked for me. I want to know why my code didn't work
#Component
public class DataProvider {
public int method1() {
//somecode
}
}
public enum Genres {
DRAMA(1,”Drama”);
ADVENTURE(2,”Adventure”);
HORROR(3,”Horror”);
private int id;
private String name;
#Inject DataProvider dataprovider;
public int someMethod() {
return dataprovider.method1();
}
}

What the answer you linked does is loop the enum values and use a setter to inject the DataProvider dependency
public void postConstruct() {
for (ReportType rt : EnumSet.allOf(ReportType.class)) {
rt.setDataPrepareService(dataPrepareService);
}
}
It works because the ReportTypeServiceInjector class is an inner, static class, and so it can be seen and instantiated by Spring.
It's a crazy design anyway. Avoid it.
Ultimately, keep the enum simple and extract the DataProvider usage.
Your original code didn't work because Spring cannot #Autowire/#Inject dependencies in enums.

Generally, it is not a good practice to have dependency injection in enums as they are designed to be constants/static (Reference)
But, I agree with you, many times, we need to associate some real time behavior to be encapsulated along with Enum values.
I would suggest, create a new class and encapsulate Enum within that.
class GenresService{
// 1st option: Declare Genres enum reference at class level and
// initialize using class constructor/injection.
// Genres g;
#Inject DataProvider dataprovider;
//2nd option: pass Genres value to method at real time.
public int someMethod(Genres g) {
return dataprovider.method1();
}
}

To have any injection to work you would need to have your enum also managed. You could try to inject your enum but how and what would you inject? It presents constant values and in addition it has private no args constructor.
So the way you might have it working would be some JNDI lookup - that initializes dataProvider - inside your someMethod() or using some static context accessor.
And: for for Spring it is not #Inject but #Resource or #Autowired

Related

ReflectionTestUtils set field method

Is there a way to use ReflectionTestUtils to set the return value of a method inside a field that represents a class to a mocked value instead of mocking the entire field? I was trying .setField(), but that only seems to work for the entire field. If there isn't, what would be a good substitute? Example of what I mean below:
public class Example() {
private ClassField field;
public methodThatUsesField() {
methodReturnType type = field.method(); // I was trying to call .setField() to change the field's method to a mocked value, but can't figure out how to do it
...
}
}
The class that is called in the field is very complicated, but there is a very simple public method that acts as the root of the class, and I want to set that to a specific value. The class itself does not have a constructor, so I need a way to get around that.
This is a spring boot project written in Java, and I need to use ReflectionTestUtils to be able to pass an argument into Mockito mock
You can use Mockito.spy(field) and inject spied field using ReflectionTestUtils. Something like this
#SpringBootTest
class ExampleTest {
#Autowired
private Example example;
#Autowired
private ClassField field;
#Test
void testMethodThatUsesField() {
ClassField spiedField = Mockito.spy(field);
Mockito.when(spiedField.method()).thenReturn(methodReturnTypeValue);
ReflectionTestUtils.setField(example, "field", spiedField);
example.methodThatUsesField();
// assertions
}
}

Create #Bean for mi method static [duplicate]

With this class
#Component
public class Sample {
#Value("${my.name}")
public static String name;
}
If I try Sample.name, it is always 'null'. So I tried this.
public class Sample {
public static String name;
#PostConstruct
public void init(){
name = privateName;
}
#Value("${my.name}")
private String privateName;
public String getPrivateName() {
return privateName;
}
public void setPrivateName(String privateName) {
this.privateName = privateName;
}
}
This code works. Sample.name is set properly. Is this good way or not? If not, is there something more good way? And how to do it?
First of all, public static non-final fields are evil. Spring does not allow injecting to such fields for a reason.
Your workaround is valid, you don't even need getter/setter, private field is enough. On the other hand try this:
#Value("${my.name}")
public void setPrivateName(String privateName) {
Sample.name = privateName;
}
(works with #Autowired/#Resource). But to give you some constructive advice: Create a second class with private field and getter instead of public static field.
Soruce of this info is this: https://www.baeldung.com/spring-inject-static-field
Spring uses dependency injection to populate the specific value when it finds the #Value annotation. However, instead of handing the value to the instance variable, it's handed to the implicit setter instead. This setter then handles the population of our NAME_STATIC value.
#RestController
//or if you want to declare some specific use of the properties file then use
//#Configuration
//#PropertySource({"classpath:application-${youeEnvironment}.properties"})
public class PropertyController {
#Value("${name}")//not necessary
private String name;//not necessary
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
}
This is my sample code for load static variable
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class OnelinkConfig {
public static int MODULE_CODE;
public static int DEFAULT_PAGE;
public static int DEFAULT_SIZE;
#Autowired
public void loadOnelinkConfig(#Value("${onelink.config.exception.module.code}") int code,
#Value("${onelink.config.default.page}") int page, #Value("${onelink.config.default.size}") int size) {
MODULE_CODE = code;
DEFAULT_PAGE = page;
DEFAULT_SIZE = size;
}
}
For those who want to use ApplicationContext in the main class of a Spring Boot application, you can just use the return value of SpringApplication.run.
Although workarounds may need to be implemented, one should try to avoid them in most scenarios if possible. Spring is great at handling dependency injection and treats most objects as Singletons. This means that Spring can handle the creation of objects for you, and the injection of these objects at runtime. When combining this with the fact that your Spring managed bean is likely a Singleton, the use of static methods and variables is largely unnecessary. You can simply autowire in an instance of the object you are looking for at the constructor level or variable level and reference the non-static version of the method or variable. This is ideal and behaves similarly to a static reference. Non static variables are basically static because you are only ever using one instance of the object in every part of the code and because of dependency injection you are never handling the instantiation of the object, just like with a static reference! Great! Now I'm sure there are instances where you need the work around (i.e. you aren't using dependency injection or class is not a singleton), but try to not use workarounds if possible. Also this is just my 2 cents. Someone may be able to offer 3. (:
public class InjectableClass{
#Value("${my.value}")
private String myString;
public String nonStaticMethod(){
return myString;
}
}
public class LogicClass{
private InjectableClass injectableClass;
#Autowire
public LogicClass(InjectableClass injectableClass){
this.injectableClass = injectableClass;
}
public void logicClassMethod(){
System.out.println("Hey! Here is the value I set on myString: " +
injectableClass.nonStaticMethod() + ". That was
basically like using a static method!");
}
}

Passing one instance of an object to different classes without using static or singleton

I am trying to figure out a way to pass one instance of the same class to multiple classes so I am able to build an object. The problem is it cannot be static or use singleton because many users will be hitting the application at the same time and I may run into other issues. Are there any design patterns that would work best with this scenario or if there is some way to use global variables in java? I am trying implement this with an existing rest service that was not designed very well.
public class OneInstanceOf
{//I want to build this map object without static
private Map<String, String> mapIwantToBuild = new HaspMap<String, String>();
public void methodIwantToCall(String name, String value)
{mapIwantToBuild.put(name, value)
}
The common pattern for you task is dependency injection. You can use spring framework for that task.
1.Create configuration with your bean:
#Configuration
public class YourConfiguration {
#Bean
public OneInstanceOf oneInstanceOf {
return new OneInstanceOf();
}
}
2.Inject your bean whatever you want (simplest - use autowiring):
#Component
public class Client1 {
#Autowire
private OneInstanceOf oneInstanceOf;
public void someMethod() {
oneInstanceOf.methodIwantToCall();
}
}
Spring will insure single instance of oneInstanceOf will be injected in all clients.
U can create a setter with parameter of instance class variable, in every class in which you want to pass the instance. Then create a method in one of the classes that calls setter of all those classes and pass parameter instance as parameter to that method.
Like below.
class A{
B b = new B;
set(B b){
C.setB(b);
D.setB(b);
E.setB(b);
}
}

#value with static field in spring [duplicate]

With this class
#Component
public class Sample {
#Value("${my.name}")
public static String name;
}
If I try Sample.name, it is always 'null'. So I tried this.
public class Sample {
public static String name;
#PostConstruct
public void init(){
name = privateName;
}
#Value("${my.name}")
private String privateName;
public String getPrivateName() {
return privateName;
}
public void setPrivateName(String privateName) {
this.privateName = privateName;
}
}
This code works. Sample.name is set properly. Is this good way or not? If not, is there something more good way? And how to do it?
First of all, public static non-final fields are evil. Spring does not allow injecting to such fields for a reason.
Your workaround is valid, you don't even need getter/setter, private field is enough. On the other hand try this:
#Value("${my.name}")
public void setPrivateName(String privateName) {
Sample.name = privateName;
}
(works with #Autowired/#Resource). But to give you some constructive advice: Create a second class with private field and getter instead of public static field.
Soruce of this info is this: https://www.baeldung.com/spring-inject-static-field
Spring uses dependency injection to populate the specific value when it finds the #Value annotation. However, instead of handing the value to the instance variable, it's handed to the implicit setter instead. This setter then handles the population of our NAME_STATIC value.
#RestController
//or if you want to declare some specific use of the properties file then use
//#Configuration
//#PropertySource({"classpath:application-${youeEnvironment}.properties"})
public class PropertyController {
#Value("${name}")//not necessary
private String name;//not necessary
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
}
This is my sample code for load static variable
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class OnelinkConfig {
public static int MODULE_CODE;
public static int DEFAULT_PAGE;
public static int DEFAULT_SIZE;
#Autowired
public void loadOnelinkConfig(#Value("${onelink.config.exception.module.code}") int code,
#Value("${onelink.config.default.page}") int page, #Value("${onelink.config.default.size}") int size) {
MODULE_CODE = code;
DEFAULT_PAGE = page;
DEFAULT_SIZE = size;
}
}
For those who want to use ApplicationContext in the main class of a Spring Boot application, you can just use the return value of SpringApplication.run.
Although workarounds may need to be implemented, one should try to avoid them in most scenarios if possible. Spring is great at handling dependency injection and treats most objects as Singletons. This means that Spring can handle the creation of objects for you, and the injection of these objects at runtime. When combining this with the fact that your Spring managed bean is likely a Singleton, the use of static methods and variables is largely unnecessary. You can simply autowire in an instance of the object you are looking for at the constructor level or variable level and reference the non-static version of the method or variable. This is ideal and behaves similarly to a static reference. Non static variables are basically static because you are only ever using one instance of the object in every part of the code and because of dependency injection you are never handling the instantiation of the object, just like with a static reference! Great! Now I'm sure there are instances where you need the work around (i.e. you aren't using dependency injection or class is not a singleton), but try to not use workarounds if possible. Also this is just my 2 cents. Someone may be able to offer 3. (:
public class InjectableClass{
#Value("${my.value}")
private String myString;
public String nonStaticMethod(){
return myString;
}
}
public class LogicClass{
private InjectableClass injectableClass;
#Autowire
public LogicClass(InjectableClass injectableClass){
this.injectableClass = injectableClass;
}
public void logicClassMethod(){
System.out.println("Hey! Here is the value I set on myString: " +
injectableClass.nonStaticMethod() + ". That was
basically like using a static method!");
}
}

How to avoid actual method call while running through junit test case

I have the following scenario.
A class MyClass in which I have an API myAPI() whose contents are as follows:
class MyClass {
public void myAPI() {
...
MyOtherClass myOtherObj = new MyOtherClass();
String value = myOtherObj.decodeAndGetName();
...
}
}
Here we have MyOtherClass which contains an API decodeAndGetName() which does some operation. It is in a different package and I can't modify its code.
Requirement
I need to write a junit test for the above myAPI(). Now I want to somehow mock the object of MyOtherClass and mock the return value of decodeAndGetName().
I am not able to do this, as we have a new MyOtherClass() and as soon as the flow comes to this line, it creates a new instance and goes to the decodeAndGetName() API.
What I need is, some way to prevent the flow going to decodeAndGetName() and take a mock value instead when this call is encountered in the above code.
Please let me know a way to do this.
I've only used it with Android code, but I think you may be able to make use of something like Mockito to mock the MyOtherClass in your tests with code similar to:
MyOtherClass mockMyOtherClass = Mockito.mock(MyOtherClass.class);
when(mockMyOtherClass.decodeAndGetName()).thenReturn(new String("known return value");
I would also suggest using dependency injection and make use of something like Guice in order to accomplish this. I use the combination of Guice & Mockito on a daily basis with my Android projects to successfully accomplish exactly this sort of thing.
Brief Example
Here is what your code may look like after setting up dependency injection with Guice:
MyOtherClassWrapper.java
#Singleton
public class MyOtherClassWrapper {
private MyOtherClass myOtherClass = new MyOtherClass();
public String decodeAndGetName() {
return getMyOtherClass().decodeAndGetName();
}
...
private MyOtherClass getMyOtherClass() {
return myOtherClass;
}
}
MyClass.java
class MyClass {
...
#Inject private MyOtherClassWrapper myOtherClassWrapper;
...
public void myAPI() {
...
String value = getMyOtherClassWrapper().decodeAndGetName();
...
}
private MyOtherClass getMyOtherClassWrapper() {
return myOtherClassWrapper;
}
}
Please see the Guice User's Guide for info on how to get started setting up Guice. It's not too difficult.

Categories