I am newbie to Spring Framework.I have tried following example in spring.
#Path("/XZY")
#Service
#Transactional
public class XZY {
#Autowired
SampleDAO sampleDao;
#Autowired
TestDAO testDao;
#Autowired
XZYinterface xzyinterface;
#POST
#Produces("text/plain")
#Path("/checkservice")
public Response XZYservice(#FormParam("Code") String Code,
#FormParam("source") String source,
#FormParam("value") String value) {
//return xzyinterface.checkXYZService(Code,sourceName,source);
XZYinterface xyz = ServiceFactory.getXZY(999);
return xyz.checkXYZService(Code,sourceName,source);
}
}
The following code will use to create singleton object
public class Singleton {
private static sampleA sampleClassA=null;
private static SampleB sampleClassB=null;
public static XZYAbstract getXZY(long id){
if(id == 999){
if(sampleClass == null){
sampleClassA = new sampleA();
}
return sampleClass;
}
if(id == 9999){
sampleClassB = new sampleA();
}
return sampleClassB;
}
}
Interface
public interface XZYinterface {
Response XZYservice(String Code, String source,String value)
}
Abstract class and implements Interface
public class XZYAbstract implements XZYinterface {
public XZYAbstract(){
super();
}
#Autowired
SampleDAO sampleDao;
#Autowired
TestDAO testDao;
public Response checkXYZService(String Code,String source,String value){
String sample = sampleDao.getValue(code);
//..source code
}
}
The following class extends abstract class.
public class sampleA extends XZYAbstract {
//some methods.
}
If i run the application it throws following errors
SEVERE [com.sun.jersey.spi.container.ContainerResponse] The RuntimeException could not be mapped to a response, re-throwing to the HTTP container: java.lang.NullPointerException
at com.test.xyz.XZYAbstract.checkXYZService(XZYAbstract.java:112) [:]
at com.test.XYZ.XZYservice(XZY.java:140) [:]
If i call directly without singleton object, values are initialized properly using Auto wired (//return xzyinterface.checkXYZService(Code,sourceName,source);) and it's working fine.
Throw from singleton object, values(sampleDAo,testDao) are not initialized properly.
How to resolve this error?
The reason is quite trivial: it's because Spring is just a library, and not a change to the Java language. Spring doesn't instrument nor enhance constructors, so the only way to get initialized Spring bean is to get it from the Spring context.
If you call new Bean(), you becomes Bean instance untouched by Spring.
For the question how to use singleton bean: do nothing. Spring beans are Singletons by default. You can specify other scope via #org.springframework.beans.factory.config.Scope annotation. See for example #Scope("prototype") bean scope not creating new bean, how it works.
Related
I am new at spring MVC framework and i am currently working in a web application that uses a session scoped bean to control some data flow.
I can access these beans in my application context using #Autowired annotation without any problem in the controllers. The problem comes when I use a class in service layer that does not have any request mapping (#RequestMapping, #GetMapping nor #PostMapping) annotation.
When I try to access the application context directly or using #Autowired or even the #Resource annotation the bean has a null value.
I have a configuration class as follow:
#Configuration
#EnableAspectJAutoProxy
#EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class, basePackages = "com.quantumx.nitididea.NITIDideaweb.repository")
public class AppConfig implements WebMvcConfigurer {
#Bean (name = "lastTemplate")
#SessionScope
public LastTemplate getlastTemplate() {
return new LastTemplate();
}
//Some extra code
}
The POJO class is defined as :
public class LastTemplate {
private Integer lastId;
public LastTemplate(){
}
public Integer getLastId() {
return lastId;
}
public void setLastId(Integer lastId) {
this.lastId = lastId;
}
}
The I have a Test class that is annotated as service and does not have any request mapping annotated method:
//#Controller
#Service
public class Test {
// #Autowired
// private ApplicationContext context;
// #Autowired
#Resource(name = "lastTemplate")
public LastTemplate lastTemplate;
// #Autowired
// public void setLastTemplate(LastTemplate lastTemplate) {
// this.lastTemplate = lastTemplate;
// }
public Test() {
}
// #RequestMapping("/test")
public String testing() {
// TemplateForma last = (TemplateForma) context.getBean("lastInsertedTemplate");
// System.out.println(last);
System.out.println(lastTemplate);
// System.out.println(context.containsBean("lastTemplate"));
// System.out.println(context.getBean("lastTemplate"));
System.out.println("Testing complete");
return "Exit from testing method";
// return "/Messages/Success";
}
}
As you can see, there is a lot of commented code to show all the ways i have been trying to access my application context, using an Application context dependency, autowiring, declaring a resource and trying with a request mapping. The bean is null if no controller annotation and request mapping method is used and throws a java null pointer exception when I use the context getBean() methods.
Finally I just test my class in a controller that i have in my app:
#RequestMapping("/all")
public String showAll(Model model) {
Test test = new Test();
test.testing();
return "/Administrator/test";
}
Worth to mention that I also tried to change the scope of the bean to a Application scope and singleton, but it not worked. How can access my application context in a service class without mapping a request via controller?
Worth to mention that I also tried to change the scope of the bean to a Application scope and singleton, but it not worked
It should have worked in this case.
How can access my application context in a service class without mapping a request via controller?
Try one of these :-
#Autowired private ApplicationContext appContext;
OR
Implement ApplicationContextAware interface in the class where you want to access it.
Edit:
If you still want to access ApplicationContext from non spring managed class. Here is the link to article which shows how it can be achieved.
This page gives an example to get spring application context object with in non spring managed classes as well
What worked for me is that session scoped bean had to be removed in the application configuration declaration and moved to the POJO definition as follows:
#Component
#SessionScope
public class LastTemplate {
private Integer lastId;
public LastTemplate(){
}
public Integer getLastId() {
return lastId;
}
public void setLastId(Integer lastId) {
this.lastId = lastId;
}
}
The I just call the bean using #Autowired annotation.
I want autowire a class which implements in a Component. Here is a part of the interface:
#Service
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class GenericResourceHandlerService<T extends ResourceRequest, A extends ResultType, B extends ResourceService<T, A>> {
private final B service;
public Response get(String x) {
various checks(x, service.getType());
B res = service.get(x);
if (res!= null) {
return Response.status(Response.Status.OK).entity(res).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
}
Then, a class which implements ResourceService would look like this:
#Component
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class TypeOneService implements EntityService<CityRequest, City> {
private final Repository repository;
#Override
public ResultType getType() {
return ResultType.TYPE_ONE;
}
#Timed
public TYPE_ONE get(String resource) {
return repository.get(resource);
}
}
And the interface itself, looks like this:
public interface EntityService<T extends EntityRequest, A extends ReturnableEntity> {
ResourceType getResourceType();
A get(String resource);
}
Now, I have a set of controllers which tries to autowire GenericResourceHandlerService and call it's get method. Which looks like this:
public class TypeOneController {
private final TypeOneService typeOneService;
private final GenericResourceHandlerService<TypeOneRequest, TypeOne, TypeOneService> genericResourceHandlerService;
public Response getListItemByResource(
String resource
) {
return genericResourceHandlerService.get(resource);
}
}
Or this:
public class TypTwoController {
private final TypeTwoService typeTwoService;
private final GenericResourceHandlerService<TypeTwoRequest, TypeTwo, TypeTwoService> genericResourceHandlerService;
public Response getListItemByResource(
String resource
) {
return genericResourceHandlerService.get(resource);
}
}
This compiles but when the app starts then, then I get the following error message:
Parameter 0 of constructor in path.GenericResourceHandlerService required a single bean, but 2 were found:
- typeOneSerivce: defined in file [C:\Path\TypeOneService.class]
- typeTwoService: defined in file [C:\Path\TypeTwoService.class]
I think this is because, Spring Boot can't work out which one to service to autowire with. Is it possible what I am trying to do?
Spring tries to inject a bean to resolve the GenericResourceHandlerService.service but service has type B and B extends ResourceService. And spring found 2 beans implementing this interface so doesn't know which implementation to autowire..
You can put #Qualifier on field service but I imagine you will lost the genericity of this type GenericResourceHandlerService
Maybe the best way is to let the controller pass through the implementation in the GenericResourceHandlerService and let this last as a simple pojo..not a spring bean (so remove #Service on GenericResourceHandlerService
Like this
public class TypeOneController {
#Autowired
private final TypeOneService typeOneService;
private final GenericResourceHandlerService<TypeOneRequest, TypeOne, TypeOneService> genericResourceHandlerService = new GenericResourceHandlerService(typeOneService);
public Response getListItemByResource(
String resource
) {
return genericResourceHandlerService.get(resource);
}
}
I have a component defined with prototype scope. I want to use that component in my service class. I want spring to provide me a new instance of that Bean everytime I call for it.
Component Class:
#Getter
#Setter
#Component
#Scope("prototype")
public class ProtoTypeBean {
//.. Field variables
}
Service Class:
#AllArgsConstructor
#Service
public class ServiceClass {
ProtoTypeBean prototypeBean;
ArrayList<ProtoTypeBean> prototypeBeans;
public void demoMethod(ArrayList<String> someArrayList) {
for(var singleString: someArrayList) {
prototypeBean.setFieldValue(singleString);
prototypeBeans.add(prototypeBean);
}
System.out.println(prototypeBeans.toString());
}
}
By using this configuration, I am getting the same instance of ProtoTypeBean in my prototypeBeans ArrayList. The question is, how would I make Spring understand to give me a new instance of prototypeBean every time I am calling it into the foreach loop?
I found I can use ApplicationContext.getBean() to get a new instance of the Bean in foreach loop but I also heard that it's a bad practice. So kindly help me with the best practice.
Use an ObjectProvider to lazily get the result you want. However the first prototype scoped bean will not be represented in the list of beans as, well they are prototype scoped.
#AllArgsConstructor
#Service
public class ServiceClass {
private final ObjectProvider<ProtoTypeBean> provider;
public void demoMethod(ArrayList<String> someArrayList) {
PrototypeBean pb = provider.getIfUnique();
for(var singleString: someArrayList) {
pb.setFieldValue(singleString);
pb.add(prototypeBean);
}
System.out.println(prototypeBean.toString());
}
}
Also if you don't need all the dependency injection, proxy creation etc. for your object then why bother. There is nothing wrong with just the new keyword in a Spring application. Not everything has to be managed by Spring.
Set up your prototype bean similar to this:
#Getter
#Setter
#Component
#Scope("prototype")
public class ProtoTypeBean {
final private String param;
public ProtoTypeBean(final String p) {
this.param = p;
}
}
Now, in your service class use a BeanFactory to create the beans for you:
#Service
#AllArgsConstructor
public class ServiceClass {
private final BeanFactory factory;
private List<ProtoTypeBean> prototypeBeans;
#Autowired
public ServiceClass(final BeanFactory f) {
this.factory = f;
}
public void demoMethod(List<String> someArrayList) {
this.prototypeBeans = someArrayList
.stream()
.map(param -> factory.getBean(ProtoTypeBean.class, param))
.collect(Collectors.toList());
}
}
I came across this issue recently. I am sure there must be a better way than mine, but this is how I did it:
public class ServiceClass {
ArrayList<ProtoTypeBean> prototypeBeans = new ArrayList<>();
#Autowired
ApplicationContext ctx;
public void demoMethod(ArrayList<String> someArrayList) {
for(var singleString: someArrayList) {
//magic is in below line.. getting a bean from ApplicatioContext.
ProtoTypeBean prototypeBean= ctx.getBean("protoTypeBean"); //Or ctx.getBean(ProtoTypeBean.class);
prototypeBean.setFieldValue(qBean.getFieldValue());
prototypeBeans.add(prototypeBean);
}
System.out.println(prototypeBeans.toString());
}
This way, Spring container always give you a new instance. And it is totally managed by Spring container.
The way you tried it, I tried that as well, but it would always inject one instance at the time of autowiring, hence defeating the purpose of prototyping.
You could have gone the route of using new Keyword. But then that is just regular Java instantiation and I think that new instance is not managed by Spring because it is annotated with #Component instead of #Configuration. I could be wrong here though.
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'm having problems trying to set the mock object in my wired bean in my testcase.
Here's my simplified problem:-
class SomeClassTest {
#Autowired
private SomeClass someClass;
#Test
public void testRun() {
Service service = mock(ServiceImpl.class);
when(service.doIt()).thenReturn("");
// this line fails with ClassCastException
((SomeClassImpl) someClass).setService(service);
assertEquals("bad", someClass.run());
}
}
interface SomeClass {
String run();
}
class SomeClassImpl implements SomeClass {
private Service service;
public void setService(Service service) {
this.service = service;
}
public String run() {
String value = service.doIt();
return StringUtils.isBlank(value) ? "bad" : "good";
}
}
interface Service {
String doIt();
}
class ServiceImpl implements Service {
public String doIt() {
return "bla";
}
}
In this example, I'm trying to test SomeClass by mocking out Service.doIt() so that I can test different conditions. The problem I'm facing is I'm not sure how exactly I should set the mock Service object in SomeClass. The only way I can think of is to downcast SomeClass into the concrete class to call setService(...), however, I'm getting a ClassCastException saying $Proxy incompatible with SomeClassImpl. I believe all my bean wirings are proxy-based because I'm using AOP to configure the transaction. I really do not want to expose setService(...) in SomeClass interface because it makes no sense to do so in my production code.
Is there a way for me to accomplish this?
Thanks.
You can use the #Resource annotation to get the implementation:
#Resource
private SomeClassImpl someClass;
...
someClass.setService(service);
...
Use additional interface for Service setter than.
or
Do not autowire Service but use 'new' operator in your test.