Autowiring in classes without RequestMapping - java

I am working on three different tables. I am using Hibernate to query these tables. I implemented successfully the DAO and the service layers, but i have few problems with the controller package. Here is my code, my controller package contains 3 classes , each should handle a table (i have 3 tables as i said before).
#Controller
public class Ods_Gis_Actel_Controller {
Param_Gis_Actel_Controller Param = new Param_Gis_Actel_Controller();
Tbl_Dim_Actel_Controller Dim = new Tbl_Dim_Actel_Controller();
#Autowired
Ods_Gis_Actel_metier service;
#RequestMapping(value="/index")
public String pageIndex(Model model)
{
addOdsTable(model);
Param.addParamTable(model);
Dim.addDimTable(model);
return "Affichage";
}
public void addOdsTable(Model model)
{
model.addAttribute("listeOds",service.getAll());
}
}
#Controller
public class Param_Gis_Actel_Controller {
#Autowired
Param_Gis_Actel_metier service;
public void addParamTable(Model model)
{
model.addAttribute("listeParam",service.getAll());
}
}
#Controller
public class Tbl_Dim_Actel_Controller {
#Autowired
Tbl_Dim_Actel_metier service;
public void addDimTable(Model model)
{
model.addAttribute("listeDim",service.getAll());
}
}
The request mapping is done in the 1st class, whose method calls 2 other methods from the other classes. But it seems, that the autowiring works only in the class, where the RequestMapping is performed.
Is this true?
how can i use the other methods from the classes which don't contain the RequestMapping if the autowiring doesn't work for them?

I gone through your problem , I think you are not so much aware the objective of #Controller , #RequestMapping . So First of all you need to know , why we use #Controller?, this is used to give business logic to your request. When request is hited from user , then your DispatcherServlet match the url from your request to value of RequestMapping annotation of all defined controller. And according to that , the matched mapping method is called and further procees done by framework. Now come to #Autowire, this is used to load the bean class definition from the xml configuration. So the #Autowire and #RequestMapping having different objective . So it's wrong to say here that the
**autowiring** works only in the class where the RequestMapping is performed.
Now your second question , How you can use simple class? there are two ways to achieve that as far as I know,
1) To create the Object of that class inside your class as you done in your code
2) To create the instance of that class using factory-method.
for the second point , you have to first define your class inside the configuration file by following the below format
<bean id="paramGis" class="<whatever_package_detail>.Param_Gis_Actel_Controller" factory-method="createInstance"/>
here one things you have to care that this method should be static .
and your class would look like that
#Service
public class Param_Gis_Actel_Controller {
private static Param_Gis_Actel_Controller paramGis;
public static Param_Gis_Actel_Controller createInstance(){
if(paramGis==null){
return new Param_Gis_Actel_Controller();
}
return paramGis;
}
public void addParamTable(Model model)
{
model.addAttribute("listeParam",service.getAll());
}
}
If you are still getting problem let me know.

I think you are having difficulties with the Java/Spring way. We don't use #Controller/#Autowired like that.
It's kind of hard to explain shortly (I strongly recommend you read the official document for that), but in short, you shouldn't create a Controller object inside another controller. The objects with annotation marks (#Controller, #Service...) should be generated and managed by Spring. At initiation time they will be injected with the #Autowired services by "Spring" way. Of courses you can intervene into that process, but by other special methods.
P/s: your naming convention is not for Java ;). If you create a program for personal use it maybe ok, but you will have difficult times collaborating with other Java developers.

Through method name as default one for access that particular method or use #Qualifier annotations.

Related

Spring MVC: issue between xml and annotation configurations

I have created a simple controller
#GetMapping("/playerAccount")
public Iterable<PlayerAccount> getPlayerAccounts(com.querydsl.core.types.Predicate predicate) {
return repository.findAll(predicate);
}
When I call the GET /playerAccount API, I get the exception IllegalStateException "No primary or default constructor found for interface com.querydsl.core.types.Predicate" (thrown by org.springframework.web.method.annotation.ModelAttributeMethodProcessor#createAttribute).
After some (deep!) digging, I found out that if I delete the following line in my spring.xml file:
<mvc:annotation-driven />
And if I add the following line in my Spring.java file:
#EnableWebMvc
then the problem disappears.
I really don't understand why. What could be the cause of that ? I thought that these were really equivalent (one being a xml based configuration, the other being java/annotation based).
I read this documentation on combining Java and Xml configuration, but I didn't see anything relevant there.
edit:
from the (few) comments/answers that I got so far, I understand that maybe using a Predicate in my API is not the best choice.
Although I would really like to understand the nature of the bug, I first want to address the initial issue I'm trying to solve:
Let's say I have a MyEntity entity that is composed of 10 different fields (with different names and types). I would like to search on it easily. If I create the following (empty) interface:
public interface MyEntityRepository extends JpaRepository<MyEntity, Long>, QuerydslPredicateExecutor<MyEntity> {
}
then without any other code (apart from the xml configuration ), I am able to easily search a myEntity entity in the database.
Now I just want to expose that functionality to a Rest endpoint. And ideally, if I add a new field to my MyEntity, I want that API to automatically work with that new field, just like the MyEntityRepository does, without modifying the controller.
I thought this was the purpose of Spring Data and a good approach, but please tell me if there's a better / more common way of creating a search API to a given Entity.
I didn't see that it returned an exception, that's why I thought it was a dependency problem.
Try to make your code look like this, and it will do it.
#RestController
public class MyClass {
#Autowired
private final MyRepository repository;
#GetMapping("/playerAccount")
public Iterable<PlayerAccount> getPlayerAccounts() {
return repository.findAll();
}
If you have a parameter in your request you add #RequestParam.
Code time (yaaaaaay) :
#RestController
public class MyClass {
#Autowired
private final MyRepository repository;
#GetMapping("/playerAccount")
public Iterable<PlayerAccount> getPlayerAccounts(#RequestParam(required = false) Long id) {
return repository.findById(id);
}
Ps: the request should keep the same variable name e.g
.../playerAccount?id=6

Spring Data: multiple repository interfaces into a single 'repository' service class

I have quite some JpaRepository extended Repository interfaces due to the design of the database.
In order to construct a simple object i.e Person I have to make method calls to about 4 - 5 repositories just because the data is spread like that throughout the database. Something like this (pardon for pseudocode):
#Service
public class PersonConstructService {
public PersonConstructService(Repository repository,
RepositoryTwo repositoryTwo,
RepositoryThree repositoryThree) {
public Person constructPerson() {
person
.add(GetDataFromRepositoryOne())
.add(GetDataFromRepositoryTwo())
.add(GetDataFromRepositoryThree());
return person;
}
private SomeDataTypeReturnedOne GetDataFromRepositoryOne() {
repository.doSomething();
}
private SomeDataTypeReturnedTwo GetDataFromRepositoryTwo() {
repositoryTwo.doSomething();
}
private SomeDataTypeReturnedThree GetDataFromRepositoryThree() {
repositoryThree.doSomething();
}
}
}
PersonConstructService class uses all these interfaces just to construct a simple Person object. I am calling these repositories from different methods inside the PersonConstructService class. I have thought about spreading this class into multiple classes, but I do not think this is correct.
Instead I would like to use a repositoryService which would include all the repositories listed necessary for creation of a Person object. Is that a good approach? Is it possible in Spring?
The reason I am asking is that sometimes the count of injected Services into a class is about 7-8. This is definitely not good.
I do not think you can / shoudl create a meta-repository like abstraction. Repositories have a well defined meaning, conceptually, they are CRUD services (and a bit more sometimes :-)) for your Hibernate/JPA/Datastore entities. And I guess this is enough for them. Anything more is confusing.
Now what I would propose is a "smart" way of building your "Person" objects that is automa(g)tically aware of any new services that contribute to the meaning of the Person object.
The crux of it would be that :
you could have your Repositories implement a given Interface, say PersonDataProvider, which would have a method, say public PersonPart contributeDataToPersonBuidler(PersonBuilder).
You would make your #Service implement Spring's BeanFactoryPostProcessor interface, allowing you to inspect the container for all such PersonDataProvider instances, and inject them to your service (see accepted answer at How to collect and inject all beans of a given type in Spring XML configuration)
Your #Service implementation would then be to ask all the PersonDataProviders in turn to ask them to contribute their data.
I could expand a bit, but this seems to me like the way to go.
One could argue that this is not clean (it makes your Repositories aware of "something" that happens at the service layer, and they should not have to), and one could work around that, but it's simpler to expose the gist of the solution that way.
EDIT : since this post was first written, I came aware that Spring can auto-detect and inject all beans of a certain type, without the need of PostProcessors. See the accepted answer here : Autowire reference beans into list by type
I see it as a quite reasonable and practical data aggregation on Service layer.
It's perfectly achievable in Spring. If you have access to repositories code you can name them all like:
#Repository("repoOne")
public class RepositoryOne {
#Repository("repoTwo")
public class RepositoryTwo {
And inject them into the aggregation service as necessary:
#Service
public class MultipleRepoService {
#Autowired
#Qualifier("repoOne")
private RepositoryOne repositoryOne;
#Autowired
#Qualifier("repoTwo")
private RepositoryTwo repositoryTwo;
public void doMultipleBusiness() {
repositoryOne.one();
repositoryTwo.two();
}
}
In fact, you even don't need to name and Qualify them if they are different classes, but if they are in hierarchy or have the same interface...
Also, you can inject directly to constructing method if autowiring is not a case:
public void construct(#Qualifier("repoOne")RepositoryOne repoOne,
#Qualifier("repoTwo")RepositoryTwo repoTwo) {
repoOne.one();
repoTwo.two();
}

REST controllers with same Path

I'm using Spring frame work with jersey to implement REST.
I have a 2 sets of paths in the following patterns
Set 1:
/top/{top_id}/<some string>
ex:
/top/{top_id}/book
/top/{top_id}/pen
/top/{top_id}/dog
Set 2 :
/top/{top_id}/middle/{middle_id}/<some string>
ex:
/top/{top_id}/middle/{middle_id}/book
/top/{top_id}/middle/{middle_id}/pen
/top/{top_id}/middle/{middle_id}/dog
Since these work on different levels ( set 1 on top level and set 2 on middle level) , I want to create different controllers classes for them.
#Component
public class Top{
}
#Component
public class Middle{
}
The problem I'm having is both sets have /top/{top_id} common.
I don't know what to use as the value for #Path annotation written above the class. I tried removing it, but Jersey is not recognizing the class. Please suggest a method to implement this. I'm trying to do this because there are around 100 paths in each layer. I don't want to keep them all together in a single file. Thank you.
After going through orcale docs , I found a way to make it work.
#Path("/top/{top_id}")
#Component
public class Top{
#GET
#Path("/book")
#Produces({"application/json"})
public getBooks(){
}
}
#Path("/top/{top_id}/middle/{middle_id}")
#Component
public class Middle{
#GET
#Path("/book")
#Produces({"application/json"})
public getBooks(){
}
}
It works. Using like this they can be split into different controller files.

what is the difference between using or not Spring Beans?

Probably i'll get a lot of downvotes, but it's so confusing for me all this fact of whether use beans or not. Lets suppose this example
interface ICurrency {
String getSymbol();
}
public class CurrencyProcessor {
private ICurrency currency ;
public CurrencyProcessor(ICurrency currency) {
this.currency = currency;
}
public void doOperation(){
String symbol = currency.getSymbol();
System.out.println("Doing process with " + symbol + " currency");
// Some process...
}
}
So, to inject the ICurrency impl injection i think that i can do it by two ways:
Way 1: Without Spring beans
public class CurrencyOperator {
private ICurrency currency ;
private CurrencyProcessor processor;
public void operateDefault(){
currency = new USDollarCurrency();
processor = new CurrencyProcessor(currency)
this.processor.doOperation();
}
}
Where USDollarCurrency is an ICurrency interface implementation
Way 2: Using Spring beans
#ContextConfiguration(classes = CurrencyConfig.class)
public class CurrencyOperator {
#Autowired private ICurrency currency ;
#Autowired private CurrencyProcessor processor;
public void operateDefault(){
this.processor.doOperation();
}
}
#Configuration
public class CurrencyConfig {
#Bean
public CurrencyProcessor currencyProcessor() {
return new CurrencyProcessor(currency());
}
#Bean
public ICurrency currency() {
return new USDollarCurrency();
}
I really don't understand what would be the benefits of using Spring's beans. I read some things but what i most found was about the benefits of using DI, and as i understand, both ways are injecting the dependency that CurrencyProcessor require, what is changing is the way that i am creating and using objets, am i wrong? So in concrete, my questions are:
1. What are the benefits of using Beans at this case?
2. Why should i use Spring instead of doing it manually like first way?
3. Talking about performance, which of this cases is better?
Suppose you have 2 DAO classes one for Oracle, the seconde for MySQL, and both classes are implementing a DAO interface. You define an implementation as a bean in Spring configuration file. In the business class you have an attribut of type DAO, while in the spring configuration file you choose the real type wheather Oracle or MySQL to inject or using spring annotation #Autowired
This reduce coupling and it will be easy to move from Oracle to MySQL.
#Service
public class Business {
#Autowired
private Dao daoImpl;
//Business methods that invoks Dao methods
}
In the Spring configuration file (XML file) you use the following:
<bean id="daoImpl" class="app.com.MySQLDaoImpl OR app.com.OracleDaoImpl"/>
By just changing the class attribut of your bean you change the whole implementation, without any change in your business class ! Good luck.
Your example without Spring doesn't dependency injection!
With dependency injection, the actual implementation of the interface is determined outside the code itself in order to reduce the coupling!
You should be able to need another implementation (you could for example switch from one JMS client to another...).
To answer to your last question, using Spring is (a very little bit) less performant but much more flexible.
EDIT :
Spring is not the only tool that can be used for DI but it is the most popular and it contains a lot of features. Note that many Java standards also (such as JPA) use DI.

RequestMapping annotation leads to empty RequestMethod array when looking up annotation for the controller method

We're building some kind of automatic self describing REST service (live doc generation). For this we have a controller method that looks for all controller beans and fetches also the requestmapping information to display them in a nice friendly html page.
For this we use the MetadataReader (created via CachingMetadataReaderFactory) to fetch the Metadata of the class.
When we get the MethodMetaData for the public methods we find the RequestMapping annotation along with produces and value parameters, but the method field is always an empty array, although we have it configured in the source code and the mapping works. So the information should be somewhere. This is quite puzzling! :-)
EDIT: method field is empty=> The RequestMapping Annotation has a method field, which is an array of RequestMethod objects. If you try to read that from the MethodMetaData instance it's an empty array. Example: metadata.getAnnotationAttributes(RequestMapping.class.getName()).get("method")
I tried to find the reason in the spring framework source code, but haven't found the reason so far...
Any ideas?
FYI: We're using Spring 3.1
I created a little sample project out of my own curiosity and fiddled a little with the MetadataReader provided by Spring. For the demo I created a very simple controller which looked like this:
#Controller
public class SomeAnnotatedController {
#RequestMapping(method = {RequestMethod.GET}, value = "/someUrl")
public void someMethod() {
// do something later
}
}
I was not able to extract the correct information from the annotation using the Spring MetadataReader.
#Test
public void shouldReturnMethodArrayWithSpringMetadataReader() throws Exception {
MetadataReader metadataReader = new CachingMetadataReaderFactory().getMetadataReader(SomeAnnotatedController.class.getName());
Set<MethodMetadata> annotatedMethods = metadataReader.getAnnotationMetadata().getAnnotatedMethods(RequestMapping.class.getName());
assertEquals(1, annotatedMethods.size());
MethodMetadata methodMetadata = annotatedMethods.iterator().next();
assertEquals("someMethod", methodMetadata.getMethodName());
Map<String, Object> annotationAttributes = methodMetadata.getAnnotationAttributes(RequestMapping.class.getName());
assertTrue(annotationAttributes.containsKey("method"));
RequestMethod[] methodAttribute = (RequestMethod[]) annotationAttributes.get("method");
assertEquals(1, methodAttribute.length);
}
Running this test fails in the last line and tells you that this is an empty array...
java.lang.AssertionError:
Expected :1
Actual :0
Doing the same with native Java feels a little bit easier and returns the correct information.
#Test
public void shouldReturnMethodArrayWithPlainJava() throws Exception {
Method method = SomeAnnotatedController.class.getDeclaredMethod("someMethod");
RequestMapping annotation = method.getAnnotation(RequestMapping.class);
assertEquals(1, annotation.method().length);
assertEquals(RequestMethod.GET, annotation.method()[0]);
}
So I am sorry to tell you that I did not find a solution to the problem but maybe the sample project or the documented alternative based on plain java might help.
This is not a direct answer to what you have asked for, but is a very good way to do self-document the REST API's. Use the endpoint documentation controller described by Rossen Stoyanchev here in his github location: https://github.com/rstoyanchev/spring-mvc-31-demo.git
to summarize, your controller would look something like this:
#Controller
public class EndpointDocController {
private final RequestMappingHandlerMapping handlerMapping;
#Autowired
public EndpointDocController(RequestMappingHandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
}
#RequestMapping(value="/endpointdoc", method=RequestMethod.GET)
public void show(Model model) {
model.addAttribute("handlerMethods", this.handlerMapping.getHandlerMethods());
}
}
and your jsp would refer to the attributes for method, produces, consumes, method signature this way, asssuming the hm is a handler method:
Patterns:${hm.key.patternsCondition.patterns}
Method: ${hm.key.methodsCondition.methods}
Method signature: ${hm.value}
Consumes: ${hm.key.consumesCondition.expressions}
Produces: ${hm.key.producesCondition.expressions}

Categories