I have the DataPrepareService that prepare data for reports and I have an Enum with report types, and I need to inject ReportService into Enum or have access to ReportService from enum.
my service:
#Service
public class DataPrepareService {
// my service
}
my enum:
public enum ReportType {
REPORT_1("name", "filename"),
REPORT_2("name", "filename"),
REPORT_3("name", "filename")
public abstract Map<String, Object> getSpecificParams();
public Map<String, Object> getCommonParams(){
// some code that requires service
}
}
I tried to use
#Autowired
DataPrepareService dataPrepareService;
, but it didn't work
How can I inject my service into enum?
public enum ReportType {
REPORT_1("name", "filename"),
REPORT_2("name", "filename");
#Component
public static class ReportTypeServiceInjector {
#Autowired
private DataPrepareService dataPrepareService;
#PostConstruct
public void postConstruct() {
for (ReportType rt : EnumSet.allOf(ReportType.class))
rt.setDataPrepareService(dataPrepareService);
}
}
[...]
}
weekens' answer works if you change inner class to static so spring can see it
Maybe something like this:
public enum ReportType {
#Component
public class ReportTypeServiceInjector {
#Autowired
private DataPrepareService dataPrepareService;
#PostConstruct
public void postConstruct() {
for (ReportType rt : EnumSet.allOf(ReportType.class))
rt.setDataPrepareService(dataPrepareService);
}
}
REPORT_1("name", "filename"),
REPORT_2("name", "filename"),
...
}
There is one another approach you may like to explore. However instead of injecting a bean into enum it associates a bean with an enum
Say you have an enum WidgetType and Widget class
public enum WidgetType {
FOO, BAR;
}
public class Widget {
WidgetType widgetType;
String message;
public Widget(WidgetType widgetType, String message) {
this.widgetType = widgetType;
this.message = message;
}
}
And you want to create Widgets of this type using a Factory BarFactory or FooFactory
public interface AbstractWidgetFactory {
Widget createWidget();
WidgetType factoryFor();
}
#Component
public class BarFactory implements AbstractWidgetFactory {
#Override
public Widget createWidget() {
return new Widget(BAR, "A Foo Widget");
}
#Override
public WidgetType factoryFor() {
return BAR;
}
}
#Component
public class FooFactory implements AbstractWidgetFactory {
#Override
public Widget createWidget() {
return new Widget(FOO, "A Foo Widget");
}
#Override
public WidgetType factoryFor() {
return FOO;
}
}
The WidgetService is where most of the work happens. Here I have a simple AutoWired field which keeps tracks of all the registered WidgetFactories. As a postConstruct operation we create a map of the enum and the associated factory.
Now clients could inject the WidgetService class and get the factory for the given enum type
#Service
public class WidgetService {
#Autowired
List<AbstractWidgetFactory> widgetFactories;
Map<WidgetType, AbstractWidgetFactory> factoryMap = new HashMap<>();
#PostConstruct
public void init() {
widgetFactories.forEach(w -> {
factoryMap.put(w.factoryFor(), w);
});
}
public Widget getWidgetOfType(WidgetType widgetType) {
return factoryMap.get(widgetType).createWidget();
}
}
Enums are static, so you have to figure out a way to access to the beans from a static context.
You can create a class named ApplicationContextProvider that implements the ApplicationContextAware interface.
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ApplicationContextProvider implements ApplicationContextAware{
private static ApplicationContext appContext = null;
public static ApplicationContext getApplicationContext() {
return appContext;
}
public void setApplicationContext(ApplicationContext appContext) throws BeansException {
this.appContext = appContext;
}
}
then add this your application context file:
<bean id="applicationContextProvider" class="xxx.xxx.ApplicationContextProvider"></bean>
after that you could access to the application context in a static way like this:
ApplicationContext appContext = ApplicationContextProvider.getApplicationContext();
it will be hard to control that the spring container is already up and running at the time the enum is instantiated (if you had a variable with this type in a test-case, your container will usually not be there, even aspectj autowiring won't help there). i would recommend to just let the dataprepare-service or something give you the specific-params with a lookup-method with the enum-parameter.
I think this what you need
public enum MyEnum {
ONE,TWO,THREE;
}
Autowire the enum as per usual
#Configurable
public class MySpringConfiguredClass {
#Autowired
#Qualifier("mine")
private MyEnum myEnum;
}
Here is the trick, use the factory-method="valueOf" and also make sure
lazy-init="false"
so the container creates the bean upfront
<bean id="mine" class="foo.bar.MyEnum" factory-method="valueOf" lazy-init="false">
<constructor-arg value="ONE" />
</bean>
and you are done!
Just pass it to the method manually
public enum ReportType {
REPORT_1("name", "filename"),
REPORT_2("name", "filename"),
REPORT_3("name", "filename")
public abstract Map<String, Object> getSpecificParams();
public Map<String, Object> getCommonParams(DataPrepareService dataPrepareService){
// some code that requires service
}
}
As long as you call the method only from managed beans, you can inject it in these beans and pass the reference to the enum on each call.
Maybe you can use this solution ;
public enum ChartTypes {
AREA_CHART("Area Chart", XYAreaChart.class),
BAR_CHART("Bar Chart", XYBarChart.class),
private String name;
private String serviceName;
ChartTypes(String name, Class clazz) {
this.name = name;
this.serviceName = clazz.getSimpleName();
}
public String getServiceName() {
return serviceName;
}
#Override
public String toString() {
return name;
}
}
And in another class which you need the bean of the Enum :
ChartTypes plotType = ChartTypes.AreaChart
Object areaChartService = applicationContext.getBean(chartType.getServiceName());
Related
Is there some way to use #Autowired with static fields. If not, are there some other ways to do this?
In short, no. You cannot autowire or manually wire static fields in Spring. You'll have to write your own logic to do this.
#Component("NewClass")
public class NewClass{
private static SomeThing someThing;
#Autowired
public void setSomeThing(SomeThing someThing){
NewClass.someThing = someThing;
}
}
#Autowired can be used with setters so you could have a setter modifying an static field.
Just one final suggestion... DON'T
Init your autowired component in #PostConstruct method
#Component
public class TestClass {
private static AutowiredTypeComponent component;
#Autowired
private AutowiredTypeComponent autowiredComponent;
#PostConstruct
private void init() {
component = this.autowiredComponent;
}
public static void testMethod() {
component.callTestMethod();
}
}
Create a bean which you can autowire which will initialize the static variable as a side effect.
Wanted to add to answers that auto wiring static field (or constant) will be ignored, but also won't create any error:
#Autowired
private static String staticField = "staticValue";
You can achieve this using XML notation and the MethodInvokingFactoryBean. For an example look here.
private static StaticBean staticBean;
public void setStaticBean(StaticBean staticBean) {
StaticBean.staticBean = staticBean;
}
You should aim to use spring injection where possible as this is the recommended approach but this is not always possible as I'm sure you can imagine as not everything can be pulled from the spring container or you maybe dealing with legacy systems.
Note testing can also be more difficult with this approach.
You can use ApplicationContextAware
#Component
public class AppContext implements ApplicationContextAware{
public static ApplicationContext applicationContext;
public AppBeans(){
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
then
static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);
Disclaimer This is by no means standard and there could very well be a better spring way of doing this. None of the above answers address the issues of wiring a public static field.
I wanted to accomplish three things.
Use spring to "Autowire" (Im using #Value)
Expose a public static value
Prevent modification
My object looks like this
private static String BRANCH = "testBranch";
#Value("${content.client.branch}")
public void finalSetBranch(String branch) {
BRANCH = branch;
}
public static String BRANCH() {
return BRANCH;
}
We have checked off 1 & 2 already now how do we prevent calls to the setter, since we cannot hide it.
#Component
#Aspect
public class FinalAutowiredHelper {
#Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}
#Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}
public class ModifySudoFinalError extends Error {
private String msg;
public ModifySudoFinalError(String msg) {
this.msg = msg;
}
#Override
public String getMessage() {
return "Attempted modification of a final property: " + msg;
}
}
This aspect will wrap all methods beginning with final and throw an error if they are called.
I dont think this is particularly useful, but if you are ocd and like to keep you peas and carrots separated this is one way to do it safely.
Important Spring does not call your aspects when it calls a function. Made this easier, to bad I worked out the logic before figuring that out.
Generally, setting static field by object instance is a bad practice.
to avoid optional issues you can add synchronized definition, and set it only if private static Logger logger;
#Autowired
public synchronized void setLogger(Logger logger)
{
if (MyClass.logger == null)
{
MyClass.logger = logger;
}
}
:
Solution 1 : Using Constructor #Autowired For Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
public MyClass(MyService service) {
TestClass.service= service;
}
}
Solution 2 : Using #PostConstruct to set the value to Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
private MyService srv;
#PostConstruct
public void init() {
this.service= srv;
}
}
Refer here for more detail
I use private static inner Component: FieldSetter, to inject static field: MyBean, at last SelfDestroyBean will help me remove redundant FiledSetter bean
public final class MyClass {
private static MyBean myBean;
#Component
private static class FieldSetter extends SelfDestroyBean {
public FieldSetter(MyBean myBean) {
MyClass.myBean = myBean;
}
}
}
#SuppressWarnings("SpringJavaAutowiredMembersInspection")
public abstract class SelfDestroyBean {
#Autowired
private ApplicationContext context;
#PostConstruct
public void destroy() {
final String[] beanNames = context.getBeanNamesForType(this.getClass());
final BeanDefinitionRegistry registry =
((BeanDefinitionRegistry) context.getAutowireCapableBeanFactory());
for (String beanName : beanNames) {
registry.removeBeanDefinition(beanName);
}
}
}
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);
Is there some way to use #Autowired with static fields. If not, are there some other ways to do this?
In short, no. You cannot autowire or manually wire static fields in Spring. You'll have to write your own logic to do this.
#Component("NewClass")
public class NewClass{
private static SomeThing someThing;
#Autowired
public void setSomeThing(SomeThing someThing){
NewClass.someThing = someThing;
}
}
#Autowired can be used with setters so you could have a setter modifying an static field.
Just one final suggestion... DON'T
Init your autowired component in #PostConstruct method
#Component
public class TestClass {
private static AutowiredTypeComponent component;
#Autowired
private AutowiredTypeComponent autowiredComponent;
#PostConstruct
private void init() {
component = this.autowiredComponent;
}
public static void testMethod() {
component.callTestMethod();
}
}
Create a bean which you can autowire which will initialize the static variable as a side effect.
Wanted to add to answers that auto wiring static field (or constant) will be ignored, but also won't create any error:
#Autowired
private static String staticField = "staticValue";
You can achieve this using XML notation and the MethodInvokingFactoryBean. For an example look here.
private static StaticBean staticBean;
public void setStaticBean(StaticBean staticBean) {
StaticBean.staticBean = staticBean;
}
You should aim to use spring injection where possible as this is the recommended approach but this is not always possible as I'm sure you can imagine as not everything can be pulled from the spring container or you maybe dealing with legacy systems.
Note testing can also be more difficult with this approach.
You can use ApplicationContextAware
#Component
public class AppContext implements ApplicationContextAware{
public static ApplicationContext applicationContext;
public AppBeans(){
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
then
static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);
Disclaimer This is by no means standard and there could very well be a better spring way of doing this. None of the above answers address the issues of wiring a public static field.
I wanted to accomplish three things.
Use spring to "Autowire" (Im using #Value)
Expose a public static value
Prevent modification
My object looks like this
private static String BRANCH = "testBranch";
#Value("${content.client.branch}")
public void finalSetBranch(String branch) {
BRANCH = branch;
}
public static String BRANCH() {
return BRANCH;
}
We have checked off 1 & 2 already now how do we prevent calls to the setter, since we cannot hide it.
#Component
#Aspect
public class FinalAutowiredHelper {
#Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}
#Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}
public class ModifySudoFinalError extends Error {
private String msg;
public ModifySudoFinalError(String msg) {
this.msg = msg;
}
#Override
public String getMessage() {
return "Attempted modification of a final property: " + msg;
}
}
This aspect will wrap all methods beginning with final and throw an error if they are called.
I dont think this is particularly useful, but if you are ocd and like to keep you peas and carrots separated this is one way to do it safely.
Important Spring does not call your aspects when it calls a function. Made this easier, to bad I worked out the logic before figuring that out.
Generally, setting static field by object instance is a bad practice.
to avoid optional issues you can add synchronized definition, and set it only if private static Logger logger;
#Autowired
public synchronized void setLogger(Logger logger)
{
if (MyClass.logger == null)
{
MyClass.logger = logger;
}
}
:
Solution 1 : Using Constructor #Autowired For Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
public MyClass(MyService service) {
TestClass.service= service;
}
}
Solution 2 : Using #PostConstruct to set the value to Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
private MyService srv;
#PostConstruct
public void init() {
this.service= srv;
}
}
Refer here for more detail
I use private static inner Component: FieldSetter, to inject static field: MyBean, at last SelfDestroyBean will help me remove redundant FiledSetter bean
public final class MyClass {
private static MyBean myBean;
#Component
private static class FieldSetter extends SelfDestroyBean {
public FieldSetter(MyBean myBean) {
MyClass.myBean = myBean;
}
}
}
#SuppressWarnings("SpringJavaAutowiredMembersInspection")
public abstract class SelfDestroyBean {
#Autowired
private ApplicationContext context;
#PostConstruct
public void destroy() {
final String[] beanNames = context.getBeanNamesForType(this.getClass());
final BeanDefinitionRegistry registry =
((BeanDefinitionRegistry) context.getAutowireCapableBeanFactory());
for (String beanName : beanNames) {
registry.removeBeanDefinition(beanName);
}
}
}
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);
I have problem with injecting bean with generic types. Look at the example. I will inject to the service a repository which types takes from App class. Now i have exception:
No qualifying bean of type 'asd.IRepository' available: expected single matching bean but found 2: a,b
asd here is package, just for tests.
What can I do in this situation? Is any way to makes it?
public interface IRepository<T, V> {
void print();
}
#Component
public class A implements IRepository<String,String> {
#Override
public void print() {
System.out.println("A");
}
}
#Component
public class B implements IRepository<Double,String> {
#Override
public void print() {
System.out.println("A");
}
}
#Service
public class ServiceABC<V, T> {
#Autowired
private IRepository<V,T> repo;
public void print(){
repo.print();
}
}
#Controller
public class App {
#Autowired
private ServiceABC<String, String> serviceABC;
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext("asd");
App app = ctx.getBean(App.class);
app.serviceABC.print();
}
It looks like you don't know in advance which implementation of your IRepository interface you will need. And you will know that at runtime. In this case it is a typical case for Factory pattern where you will have a IRepositoryFactory that will have a method thhat retrieves specific implementation by type (for example IRepositoryFactory.getInstance(String type); So in your ServiceABC you may use the IRepository to get specific bean at runtime. So Factory pattern may be an answer to your question. I also wrote an article that deals with this type of problem and proposes the idea of self-populating Factory (using Open source library that provides such utility). Here is the link to the article: Non-intrusive access to "Orphaned" Beans in Spring framework
You have to name your components and autowire by name:
#Component("A")
public class A implements IRepository<String,String> {...}
#Component("B")
public class B implements IRepository<Double,String> {...}
[...]
#Autowired
#Qualifier("B")
private IRepository repo;
Something like that?
#Controller
public class RepositoryFactory {
#Autowired
private IRepository<String, String> a;
#Autowired
private IRepository<Double, String> b;
public IRepository getRepository(String className) {
if(className.equalsIgnoreCase("a")) {
return a;
} else if(className.equalsIgnoreCase("b")) {
return b;
}
return null;
}
}
#Service
public class ServiceABC {
#Autowired
private RepositoryFactory repositoryFactory;
public void print(String className){
repositoryFactory.getRepository(className).print();
}
}
#Controller
public class App {
#Autowired
private ServiceABC serviceABC;
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext("asd");
App app = ctx.getBean(App.class);
app.serviceABC.print(A.class.getSimpleName());
}
}s
I have encountered with the following issue. I would like to create Spring #Component with generic
#Component
public class ResponseDtoValidator<DTO> {
public ResponseEntity<DTO> methodToInvoke(DTO dto) {
return Optional.ofNullable(dto).map(result -> new >ResponseEntity<>
(result, HttpStatus.OK))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND)); }
}
#Controller
public class SomeController {
#Inject
private ResponseDtoValidator<DTO1> responseDtoValidator1;
#Inject
private ResponseDtoValidator<DTO2> responseDtoValidator2;
public void someMethod() {
DTO1 dto1 = new DTO1();
DTO2 dto2 = new DTO2();
responseDtoValidator1.methodToInvoke(dto1);
responseDtoValidator2.methodToInvoke(dto2);
}
}
Can I inject this Component like above? Actually, I have tried and it seems to work properly, can you please confirm that I am correct or not?
Firstly, a spring bean can not be injected in itself.
In regards to your question,yes it is injectable but dont use generic signs when injecting. Just inject it normally. Generic type is send when a method of generic class is utilizing.
For instance;
#Component
public class ResponseDtoValidator<DTO> {
public void getAbc(List<DTO> aList) {}
}
Then;
public class Test {
#Autowired // or #Inject
private ResponseDtoValidator responseDtoValidator;
public void testMethod() {
responseDtoValidator.getAbc(List<EnterATypeInHere> aList);
}
}
Is there some way to use #Autowired with static fields. If not, are there some other ways to do this?
In short, no. You cannot autowire or manually wire static fields in Spring. You'll have to write your own logic to do this.
#Component("NewClass")
public class NewClass{
private static SomeThing someThing;
#Autowired
public void setSomeThing(SomeThing someThing){
NewClass.someThing = someThing;
}
}
#Autowired can be used with setters so you could have a setter modifying an static field.
Just one final suggestion... DON'T
Init your autowired component in #PostConstruct method
#Component
public class TestClass {
private static AutowiredTypeComponent component;
#Autowired
private AutowiredTypeComponent autowiredComponent;
#PostConstruct
private void init() {
component = this.autowiredComponent;
}
public static void testMethod() {
component.callTestMethod();
}
}
Create a bean which you can autowire which will initialize the static variable as a side effect.
Wanted to add to answers that auto wiring static field (or constant) will be ignored, but also won't create any error:
#Autowired
private static String staticField = "staticValue";
You can achieve this using XML notation and the MethodInvokingFactoryBean. For an example look here.
private static StaticBean staticBean;
public void setStaticBean(StaticBean staticBean) {
StaticBean.staticBean = staticBean;
}
You should aim to use spring injection where possible as this is the recommended approach but this is not always possible as I'm sure you can imagine as not everything can be pulled from the spring container or you maybe dealing with legacy systems.
Note testing can also be more difficult with this approach.
You can use ApplicationContextAware
#Component
public class AppContext implements ApplicationContextAware{
public static ApplicationContext applicationContext;
public AppBeans(){
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
then
static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);
Disclaimer This is by no means standard and there could very well be a better spring way of doing this. None of the above answers address the issues of wiring a public static field.
I wanted to accomplish three things.
Use spring to "Autowire" (Im using #Value)
Expose a public static value
Prevent modification
My object looks like this
private static String BRANCH = "testBranch";
#Value("${content.client.branch}")
public void finalSetBranch(String branch) {
BRANCH = branch;
}
public static String BRANCH() {
return BRANCH;
}
We have checked off 1 & 2 already now how do we prevent calls to the setter, since we cannot hide it.
#Component
#Aspect
public class FinalAutowiredHelper {
#Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}
#Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}
public class ModifySudoFinalError extends Error {
private String msg;
public ModifySudoFinalError(String msg) {
this.msg = msg;
}
#Override
public String getMessage() {
return "Attempted modification of a final property: " + msg;
}
}
This aspect will wrap all methods beginning with final and throw an error if they are called.
I dont think this is particularly useful, but if you are ocd and like to keep you peas and carrots separated this is one way to do it safely.
Important Spring does not call your aspects when it calls a function. Made this easier, to bad I worked out the logic before figuring that out.
Generally, setting static field by object instance is a bad practice.
to avoid optional issues you can add synchronized definition, and set it only if private static Logger logger;
#Autowired
public synchronized void setLogger(Logger logger)
{
if (MyClass.logger == null)
{
MyClass.logger = logger;
}
}
:
Solution 1 : Using Constructor #Autowired For Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
public MyClass(MyService service) {
TestClass.service= service;
}
}
Solution 2 : Using #PostConstruct to set the value to Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
private MyService srv;
#PostConstruct
public void init() {
this.service= srv;
}
}
Refer here for more detail
I use private static inner Component: FieldSetter, to inject static field: MyBean, at last SelfDestroyBean will help me remove redundant FiledSetter bean
public final class MyClass {
private static MyBean myBean;
#Component
private static class FieldSetter extends SelfDestroyBean {
public FieldSetter(MyBean myBean) {
MyClass.myBean = myBean;
}
}
}
#SuppressWarnings("SpringJavaAutowiredMembersInspection")
public abstract class SelfDestroyBean {
#Autowired
private ApplicationContext context;
#PostConstruct
public void destroy() {
final String[] beanNames = context.getBeanNamesForType(this.getClass());
final BeanDefinitionRegistry registry =
((BeanDefinitionRegistry) context.getAutowireCapableBeanFactory());
for (String beanName : beanNames) {
registry.removeBeanDefinition(beanName);
}
}
}
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);