Spring Boot 2 | Very basic Dependency Injection #Autowired question - java

Very new to Java Spring Boot 2. Apologies in advance for what I am sure is a seriously dumb question.
Background:
For me, I need to see and understand, first of all, a very pure and simple implementation of a concept before I can begin to extrapolate the utility of the concept or technique.
Therefore I am trying to set up an idiot-proof example showing #Autowired and DI 'at work' which I can fully understand before moving on.
I have tried to set up a super simple Spring Boot 2 project with just two classes; 1 "TesterApplication" which contains the psvm and 2 'Users' which is a very simple class which contains a single field 'name', with a no args constructor. See images:
The PSVM is here:
package com.tester.kryten.tester;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class TesterApplication {
public static void main(String[] args) {
System.out.println("1. Pre Spring Run");
SpringApplication.run(TesterApplication.class, args);
System.out.println("2. Post Spring Run");
#Autowired
Users user;
System.out.println("3. " + user.getName());
}
}
The 'Users' class is here:
package com.tester.kryten.tester;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class Users {
public String name = "foo bar";
#Autowired
public Users() {
System.out.println("User class constructor called");
}
public String getName() { return name; }
}
Now, ALL I am trying to do is understand the correct way to reference and USE a Spring managed instance of 'User' in another class, in this simple example the TesterApplication class.
I am reading about how it's frowned upon to use:
Users user = new User();
And that its better to use Spring DI to manage dependencies, so how would it be done in this example?
What is throwing me is that on line 20 of the TesterApplication class I am getting the expected code completion from Intellij offering me the getName() method. This makes me think that the instance must me there, but I just get:
Error:(17, 9) java: annotation type not applicable to this kind of
declaration
Could some kind soul out there please put me out of my misery and tell me where I'm misunderstanding how to simply inject an instance of Users into TestApplication.class - the right way? Please.

Move User user; outside of main method. It have to be class property, not local variable
You do not need #Authowired annotation for constructor in Users class
You can use #Authovired annotation for constructor if it is parametrised by other Spring beans to inject them

The first thing to understand is the use of the #Component annotation. When you put the annotation on a class as in your case Users during the start of the application context, the constructor of the Users class is invoked by creating a Users object and adding it to the Spring IOC container. To use this object inside another class just create an attribute of type Users and put the #Autowired annotation on this attribute not inside the method. So you can use this attribute in the methods of your class. Also, you don't need to put the #Autowired annotation on the Users class constructor.

Related

Springboot Get Api Endpoint returns 404 not found

I'm trying to create a Springboot Get API endpoint but I get a 404 not found error' here is my code
profile.java
#Getter
#Setter
public class Profile {
private String slackUsername;
private Boolean backend;
private Integer age;
private String bio;
ProfileController
#RestController
public class ProfileController {
#Autowired
private Profile profile;
#GetMapping(path = "/profile")
private ResponseEntity<String> userInfo(){
profile.setSlackUsername("Ajava");
profile.setBackend(true);
profile.setAge(00);
profile.setBio("My name is Anakhe Ajayi, I'm learning Java everyday and I love Jesus");
return ResponseEntity.ok(profile.toString());
}
Main
#SpringBootApplication
#ComponentScan("com/ajavacode/HNGBackendStage1/api.profile")
public class HngBackendStage1Application {
public static void main(String[] args) {
SpringApplication.run(HngBackendStage1Application.class, args);
}
}
porm.xml
Please fix the value in #ComponentScan annotation like this and try again.
#SpringBootApplication
#ComponentScan(basePackages = "com.ajavacode.HNGBackendStage1")
public class HngBackendStage1Application {
public static void main(String[] args) {
SpringApplication.run(HngBackendStage1Application.class, args);
}
}
Also there is an issue in ProfileController class, you are auto wiring Profile class inside it. Profile class is not a bean so this is incorrect and userInfo() method is private, it should be public. Here is the fixed version.
#RestController
public class ProfileController {
#GetMapping(path = "/profile")
public ResponseEntity<String> userInfo(){
Profile profile=new Profile();
profile.setSlackUsername("Ajava");
profile.setBackend(true);
profile.setAge(00);
profile.setBio("My name is Anakhe Ajayi, I'm learning Java everyday and I love Jesus");
return ResponseEntity.ok(profile.toString());
}
You have to check some items in your code;
Make sure the endpoint you are sending request , is correct .
Add #RequestMapping("Profile") to the controller to avoid repeated endpoint and reduce the ambiguity
Make sure your pom is correct
Looking at your code, there are a few things to mention.
First of all, your package structure looks good (besides the fact that I, personally, would keep everything lowercase).
With the package structure that you have in place, you actually don't need any #ComponentScan annotation at all. The annotation #SpringBootApplication at your main class by default scans for components with the package of that class as the base package. So you only need to set something if you want to explicitly scan for components in some other package, e.g., either at a higher level or if you want to skip packages in the hierarchy.
Next thing is the controller. Question here is: What do you actually want to achieve?
I assume that you want to build an application that provides a GET /profile endpoint that returns a response object like the example below:
{
"slackUsername": "alice",
"backend": false,
"age": 42,
"bio": "I'm just an example"
}
If my understanding is correct, there is at least one thing that is a bit odd: Currently, you defined a controller that would return the String representation of the Profile object. That isn't necessarily something as shown in the example above. If you do not override the toString() method, the result would be something like com.ajavacode.HNGBackendStage1.api.Profile#6d06d69c (see this Baeldung article for instance). And even if you use Lombok's #Data or #ToString annotations, the result will not be a JSON or XML representation but something that is suitable for logging, for instance.
Spring will already take care of the serialization into JSON (or XML) format. In your controller you can just return the Profile object or, alternatively, a ResponseEntity<Profile>:
#GetMapping(path = "/profile")
public Profile userInfo(){
Profile profile=new Profile();
profile.setSlackUsername("Ajava");
profile.setBackend(true);
profile.setAge(00);
profile.setBio("My name is Anakhe Ajayi, I'm learning Java everyday and I love Jesus");
return profile;
}
The above example would create a response with the profile as the response body and HTTP status code 200 OK. In case you use ResponseEntity, you could also adjust the HTTP status code but in your case that probably is not necessary (yet).
Autowiring the Profile class also is not correct, as already mentioned. You only need to autowire classes beans, i.e., classes that are annotated with #Component, #Service, or #Repository. The class you "autowired" is just a POJO class representing some "data object", nothing that provides any kind of business logic.

How to use Java reflection to create an instance of an #Autowired class

I have a postgres database which stores (as a String) the relevant class to use dependent on the information coming in from the user.
e.g. user has input Name, the database has the value NameFinder() stored against this and the code needs to create an instance of NameFinder().
I was wondering if there was a way of using reflection to instantiate this class as an #Autowired component, and then call the relevant function.
I can't seem to find a guide that uses #Autowired classes so any help would be appreciated.
For autowiring to work you need the class which uses #Autowired to be a #Component (or a child like #Service ...). https://www.baeldung.com/spring-autowire
For Spring to know what to inject, you need to define a #Bean in your Configuration
https://www.baeldung.com/spring-bean
As for the reflective instantiation in the bean:
#Bean
public Name getName(Database db) {
String nameFqn = db.getConfigTable().getNameFQN();
return (Name) Class.forName(nameFqn).getConstructor().newInstance();
}
Note this uses a no-arg public constructor. FQN means fully-qualified name, i.e. com.some.pkg.NameFinder
assuming:
package com.some.pkg;
class NameFinder implements Name {
public NameFinder(){}
}
I feel like a Spring Bean should be configurable also directly from a FQN without using reflection but I don't know how. Try reading up on a BeanFactory or something similar. Usually reflection is to be avoided.

Mapping multiple graphQL schema files to separate resolvers - Spring Boot

I'm finding it really difficult to separate queries from one schema file. I want to have something like this:
car.graphqls
type Query {
car(id: ID!): Car
}
type Car {
id: ID!,
name: String!
}
house.graphqls
type Query {
house(id: ID!): House
}
type House {
id: ID!,
owner: String,
street: String
}
I searched a lot but I can't find a way to write two java classes and implement getHouse() in one of them and getCar() in other.
#Component
public class CarQuery implements GraphQLQueryResolver {
#Autowired
private CarService carService;
public List<Car> getCar(final int id) {
return this.carService.getCar(id);
}
}
public class HouseQuery implements GraphQLQueryResolver {
#Autowired
private HouseService houseService;
public List<House> getHouse(final int id) {
return this.houseService.getHouse(id);
}
}
I found out that the graphql-java-tools package which I'm using will search through the project and finds all schema files (that end with .graphqls), but the code which I showed above gives me this error:
Caused by: com.coxautodev.graphql.tools.FieldResolverError: No method found with any of the following signatures (with or without one of [interface graphql.schema.DataFetchingEnvironment] as the last argument), in priority order:
com.example.polls.resolvers.CarQuery.house(~count)
com.example.polls.resolvers.CarQuery.getHouse(~count)
I also found some advises that I need to have only one Root Query in schema files, and to extend all other Query types in schema files. I tried to write to house.graphqls something like this, but failed:
extend Type Query {
house(id: ID!): House
}
Is there a way to tell graphql and java what schema file I want to be mapped to which java resolver file?
Thanks AllirionX. Your answer was helpful.
I would just like to summarize final solution to all who are looking for answer how to create multiple schema files with separate query types in each of them and map those query types to different Java Components using GraphQLQueryResolver.
My Spring Boot project structure
I have two schema files A.graphqls and B.graphqls.
A.graphqls
---------------
type Person {
id: ID!,
name: String
}
type Query {
getPerson(id: Int):Person
}
type Mutation {
createPerson(name: String):Int
}
B.graphqls
---------------
type Book {
id: ID!,
title: String,
owner: Person
}
extend type Query {
getBooks(count: Int):[Book]
}
extend type Mutation {
deleteBook(id: Int):Int
}
schema {
query: Query,
mutation: Mutation
}
I will explain what I learned about rules we need to follow about this topic (I don't guarantee that this is all necessary, but that is how I managed to get it work how I wanted it to work).
The key here is to only have one schema definition. It doesn't matter in which file (A.graphqls or B.graphqls or C.graphqls...) - In example, I added it to B.graphqls file at the bottom.
Also, you can have only one "type Query" definition in ONE file. In all other schema files you will need to extend that type with "extend type Query" (yeah, I know, it makes sense now...). In which schema file you do that main definition for Query that is not relevant. Everything in this paragraph applies to mutations also.
You can use type defined in one .graphqls file in other .graphqls file. It will get recognized. So, in this example, you can use Person type reference in B.graphqls.
Java resolvers:
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import graphql.demo.model.Person;
import graphql.demo.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
#Component
public class AQuery implements GraphQLQueryResolver {
#Autowired
private PersonService personService;
public Person getPerson(final int id) {
return this.personService.getPerson(id);
}
}
And second one...
#Component
public class BQuery implements GraphQLQueryResolver {
#Autowired
private BookService bookService;
public List<Book> getBooks(final int count) {
return this.bookService.getBooks(count);
}
}
Names of this classes are not important. We could also have only one class that implements GraphQLQueryResolver and we could implement all query methods from both A.graphqls and B.graphqls files (getBooks() and getPerson() methods). As long as we implement all methods, it's not important in which resolver class we implemented it graphql-java will find it.
Same applies to mutations using GraphQLMutationResolver.
I have full working example (MySQL, Spring Boot, React with Apollo client) on my github, so you can check it out. There is also mysql script for generating database used in project. There is plenty of tables, but there are just for testing purposes, what is important is file structure and files I explained above. If you are not interested in client app, you can test it using graphiql, of course.
https://github.com/dusko-dime/spring-react-graphql
Hope this can be helpful to someone and thanks for helping me once again :)
Multiple schema files
Graphql-java-tools will find all the .graphqls files to build a schema instance. Multiple schema files work out of the box.
Multiple resolvers
Each resolver component must implement GraphQLQueryResolver or GraphQLMutationResolver and be scannable by spring boot. Make sure it has a #Component annotation and is in one of the spring #ComponentScan basePackages.
The error
No method found with any of the following signature means that graphql-tools was not able to find a resolver component with a method matching the signatures. In this case, the HouseQuery resolver is missing the #Component annotation.
Also there can be issue with your Resolver name
Please ensure that you specify the same name of your Resolver method as you have defined in your GraphQL Schema

Spring boot autowiring: strange case of property value being populated

I've been blown away by something and my sleep is nowhere after finding out that my code is working from last 2 years when clearly it shouldn't!
So it's a Spring boot application. The application has some controllers. One of the classes I'm using extends WebServiceGatewaySupport, so requires that I #Autowire this. The class name is AClient. Now, this class needs 4 properties to work. Three of them are coming from properties file, e.g.
#Value("${a.userName}")String userName;
So three properties are obviously picked from application.properties file. Now the fourth property had me blown away. It is NOT being fetched as rest three, but is being copied from constructor parameter. So we have only one constructor in the class:
public AClient(String d){
this.d=d;
}
Now this property is being used in one of the methods this class has
public String getSomeData(){
// This method gets Data based on property d
}
And interestingly and surprisingly, this property's value is present everytime this bean is accessed! The bean is #Autowired at one place only, inside the Controller class. I haven't marked the property value to be fetched from application.properties file. I haven't provided this class any clue where to get the value of d from. I haven't provided any public methods for other classes to set this value. Yet the code is working and I can even place a debug pointer in method getSomeData() and see that the value of d is present!
Now I understand I might be missing something obvious, but what? Is there a way I can get into Spring container when #Autowired objects are being instantiated and debug from that point to see where this value is coming from? I've checked the code multiple times. Run hundreds of query on Google to find something like Spring boot does some magic stuff to map the missing String properties. But the variable name in properties file is different from what it is in AClient class. So how can it even map? This is truly killing me now!
Addition:
Less relevant, but the code is being accessed in a standard way:
#Autowired
AClient aClient;
public someOtherMethod(){
aClient.getSomeData();
}
So when I place a debugger on first line of someOtherMethod() and hover over aClient, it shows variable d value populated, same as in application.properties file!
Edit:Here's what I missed:
#Configuration
public class someConfig{
#Bean
public AClient aClient(){
// Someone else fetched property from application.properties file, created an object of AClient class using argument constructor and returned that object here. So now Spring is using #Autowire reference for this object I guess
}
}
So basically, your #Configuration class looks similar to this?
#Configuration
public class SomeConfig {
#Value("${a-client.important-value-d}")
private String importantValueDFromApplicationProperties;
#Bean
public AClient aClient() {
return new AClient(importantValueDFromApplicationProperties);
}
}
If yes, then Spring will the aClient for every #Autowired requesting it. Therefore the value of importantValueDFromApplicationProperties will be present in this certain instance.
Another note:
I would recommend using Spring Boot's #ConfigurationProperties instead of #Value. Take a look.

What is the purpose of the Spring Bean annotation name attribute?

I'm just learning spring, and something struck me as very odd about the annotation configurations using the name attribute as a string.
#Bean(name = "com.my.injected.Service")
public InjectedService injectedService() {
return injectedService;
}
Is this name similar to the Spring Bean XML configuration id and class attributes?
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
Why isn't this simply
#Bean(clazz = com.my.injected.Service.class)
public InjectedService injectedService() {
return injectedService;
}
instead?
You're fully qualifying the path in both cases and actually using the class makes it way easier for your IDE to tell you when you've screwed it up. I understand that the XML configuration came first, and naturally it was always looking up things by string, so is this just a holdover? Is there some advantage to using strings or major disadvantage to using .class?
Question was originally based on a false premise. I edited it to spell out what this premise was and make it less confusing for new people who come along. Hopefully I did this such that the given answers are still exactly applicable; apologies if not.
#Bean annotation is meant to provide a spring bean. The type of the bean to provide will be the same type of the class/interface you define in the return method. So, instead of declaring to return a concrete class in the method, return the top (abstract) class/interface instead.
Imagine this case:
public interface MyEntityDao {
MyEntity get(String id);
}
#Repository
public class MyEntityDaoDatabaseImpl implements MyEntityDao {
#Override
public MyEntity get(String id) {
/* implementation that goes to database every time */
}
}
#Repository
public class MyEntityDaoCacheImpl implements MyEntityDao {
#Override
public MyEntity get(String id) {
/* implementation that looks the data
up in cache, never in database */
}
}
#Configuration
public class MyAppConfiguration {
#Bean
public MyEntityDaoDatabaseImpl method1() {
return new MyEntityDaoDatabaseImpl();
}
#Bean
public MyEntityDaoCacheImpl method2() {
return new MyEntityDaoCacheImpl();
}
}
#Service
public class MyEntityService {
#Autowired //what to inject here?
MyEntityDao dao;
}
In case above, there are two implementations of the proposed interface. How the framework may be able to understand which implementation to use except for the name?
#Service
public class MyEntityService {
#Autowired
#Qualifier("properBeanNameToInject")
MyEntityDao dao;
}
Bean name is not necessarily related to its class or even any of interfaces it implements. It is a name and nothing more. When you use the annotation configuration, Spring figures out what the exact class or interface the #Bean provides like the rest of java code would: either through the fully qualified name in the code or through the imports specified in the file. In your case, you presumably have an import com.my.injected.Service; statement at the top of the java file.
Your example is using the fully qualified class name as the bean name. It is your choice. You could use any other identifier. Using the fully qualified name could be useful if your code is providing an object that is named exactly like another 3rd party #Bean object that your code must include or consume. However, you could just as easily use name = "myService".
The bean name helps Spring (and application programmer) to distinguish between multiple instances of of the same bean class because you can deploy the same class as bean several times. If only one instance of bean type appear you event do not have to give it name manually: spring does this by default.
If you have several beans that have the same type or implement the same interface and you want to refer specific bean use #Qualifier annotation.

Categories

Resources