Spring not calling the default constructor - java

I have made a simple spring boot application:
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context= SpringApplication.run(DemoApplication.class, args);
Student student = context.getBean(Student.class);
System.out.println(student.getName());
#Component
public class Student {
private int id;
private String name;
public void Student(){
id = 1;
name="asd";
}
Here I have put #Component annotation on the Student class. So I can get the student object from the application context. But the id and name are not initialized as per the default constructor. What could be the reason for this? Does spring not call the default constructor automatically? If not, how is it constructing the object and putting in the applicationContext? I have also provided the setters and getters in this class. But still, the getName method is returning null.

A constructor in Java should have following rules:
Name should match class name
Constructor should not have a return type
compiler generates default constructor if there is no explicit declaration(user written constructor that looks exactly like a default one is not called default constructor)
In your code you have added return type which makes it a method , since there is no constructor written it is calling a default constructor generated by the compiler.
public Student(){
id = 1;
name="asd";
}
Removing void should fix the issue ,however this is a user defined constructor

Related

Correct way to get environment variables and go through SonarLint

I have a problem reading my environment variables and satisfying SonarLint(detect and fix quality issues) at the same time ..
That way it does not work my variable is null
private String accessKey;
#Value("${bws.access.key}")
public void setAccessKey(String ak){
accessKey=ak;
}
Changing the method to static (as the sonarLint recommends) does not work the variable continuous null
private static String accessKey;
#Value("${bws.access.key}")
public static void setAccessKey(String ak){
accessKey=ak;
}
The only way I found to work is to mark the instance variable as static but not to mark the method as static
private static String accessKey;
#Value("${bws.access.key}")
public void setAccessKey(String ak){
accessKey=ak;
}
But there sonarLint points out the issue
Instance methods should not write to "static" fields
Is not this way I'm getting my enviroment variables across the boundaries not the right one?
You can use the following code:
A Configuration Class (annotated with #Component in order to be picked up by Spring) which will hold the values coming from the properties file, where you bind the value of bws.access.key to a property directly. And if you need accessor methods for accessKey you can just create them (setAccessKey and getAccessKey)
#Component
public class ConfigClass {
// #Value("${bws.access.key:<no-value>}") // <- you can use it this way if you want a default value if the property is not found
#Value("${bws.access.key}") // <- Notice how the property is being bind here and not upon the method `setAccessKey`
private String accessKey;
// optional, in case you need to change the value of `accessKey` later
public void setAccessKey(String ak){
this.accessKey = ak;
}
public String getAccessKey() {
return this.accessKey;
}
}
For more details checkout this GitHub sample project.
I tested this with
IntelliJ IDEA 2018.1.5 (Ultimate Edition),Build #IU-181.5281.24
SonarLint
(Edit) How to use it in a Controller:
An option (there are others) could be to declare a constructor for the controller (let's call it SampleController) and request a parameter of type ConfigClass inside it. Now we set a controller attribute (config) of the same type to the value received as parameter, like this:
#RestController
public class SampleController {
private final ConfigClass config;
public SampleController(ConfigClass configClass) { // <- request the object of type ConfigClass
this.config = configClass; // <- set the value for later usage
}
#RequestMapping(value = "test")
public String test() {
return config.getAccessKey(); // <- use the object of type ConfigClass
}
}
Now, Spring Boot will try to find a component (of any type) in the app of type ConfigClass and since we have one defined it will automatically inject it in our controller. This way you can set the parameter controller property config to the value received in configClass for later usage.
In order to test it, you can request the url test. You will see that the output will be anotherValue. So we can conclude that the Dependency Injection Mechanism successfully found an instance of ConfigClass and the method ConfigClass#getAccessKey works properly.

Spring Boot - Could not find a suitable constructor error

Hi I am trying to read a file as an argument from the main class and accessing the argument in another class in Spring boot.
The main class looks like this
public class DemorestApplication extends SpringBootServletInitializer {
public static void main(String[] args) throws IOException {
new DemorestApplication().configure(new SpringApplicationBuilder(DemorestApplication.class)).run(args);
new UsersResources(args[0]);
}
}
And I am passing an argument to another class named UsersResources constructor
#Path("/sample")
public class UsersResources {
private String value;
UsersResources(String value){
this.value=value;
}
//new code
#GET
#Path("Data/file/{path}")
#Produces("application/json")
public Map<String, Map<String, List<Map<String, Map<String, String>>>>> getApplicationName1(#PathParam("path") String path) throws IOException {
ReadExceldy prop = new ReadExceldy();
FileInputStream Fs = new FileInputStream(System.getProperty("user.dir")+"\\"+value);
Properties properties = new Properties();
properties.load(Fs);
String Loc=properties.getProperty("filepath");
String Na=path;
String filename=Loc+Na;
return prop.fileToJson(filename);
}
}
I'm trying to run this code but it's throwing an error saying
java.lang.NoSuchMethodException: Could not find a suitable constructor in com.springsampleapplication.UsersResources class
at org.glassfish.jersey.internal.inject.JerseyClassAnalyzer.getConstructor(JerseyClassAnalyzer.java:192) ~[jersey-common-2.25.1.jar:na]
The issue might be with Spring trying to initialize UsersResources class and expecting a constructor with no arguments, when you have it only with a String parameter. Try adding such constructor: public UsersResources() {}
Other thought that came into mind is that this could be because of UsersResources constructor not having a visibility modifier (it means it is package protected), you could try adding public visibility modifier to it (though Spring should be able to initialize even private constructors). Are the DemorestApplication and UsersResources classes in the same package though? As otherwise the code should not compile, since UsersResources(String value) is not visible outside of the package it is in. But the error is a bit different in such case: The constructor xxx is undefined, so probably this is not the case.
Since it seems you are using Jersey you need to have a public constructor:
Root resource classes are instantiated by the JAX-RS runtime and MUST have a public constructor for which the JAX-RS runtime can provide all parameter values. Note that a zero argument constructor is permissible under this rule.
See How to register a static class in Jersey?
Since you have defined a constructor in your class, no default constructor is generated. A work around is to make this class a Spring component with #Component et al.

How to initialise #Autowired objects inside of a list which have a constructor

I have a #Service class which is called from a web request.
It has a constructor which initializes the list of objects of an implemented type
private List<Interface> interfaceServices;
#Autowired
public ValidateInterfaceService(List<Interface> interfaceServices) {
this.interfaceServices = interfaceServices;
}
This works as intended except if one of the items in the list has a constructor.
#Service
#Order(3)
public class EvaluateExampleWithConstructor implements Interface {
private LocalDate busDate;
#Autowired
public EvaluateExampleWithConstructor(LocalDate busDate) {
this.busDate = busDate;
}
If I try and have this class on the list the code cannot run as "no default constructor is found"
If the value passed into the constructor is needed for the method how do I initialize this list correctly?
Your problem is caused by the private LocalDate busDate not being a bean in the context. You can create a LocalDate for injection like this:
#Configuration
public class FooConfiguration {
#Bean
public LocalDate busDate() {
return ...
}
}
Note this looks rather weird, and you might be better off initializing this date in a different way, depending on your use-case, e.q. using #Value.

aspect is not invoked

I've got a simple aspect that supposed to set the value of class fied, that has annotation #GuiceInject.
Originally I have this
#GuiceInject(module=RepositoryModule.class)
private IRacesRepository repository;
And I expect to get similar to this
private IRacesRepository repository = GuiceInject.getInstance(IRacesRepository.class);
And here is my aspect
public aspect InjectionAspect {
Object around(): get(#GuiceInject * *) {
System.out.println(thisJoinPointStaticPart);
// instantiate object as it supposed to be null originally
return GuiceInjector.getInstance(thisJoinPoint.getTarget().getClass());
}
}
As far as I understand - I am new to AOP - it supposed to replace get invokations of the field with the code in aspect.
It compiles fine, but when I run the application - nothing happens. I get NullPointerException for readRaces method as it stays null so aspect did not work.
My main class looks like this
public class Example {
#GuiceInject(module=RepositoryModule.class)
private IRacesRepository racesRepository;
private void execute() {
System.out.println("List of races: " + racesRepository.readRaces());
}
public static void main(String[] args) {
new Example().execute();
}
}
What is the problem? Annotation has this definition
#Target(ElementType.FIELD)
// make annotation visible in runtime for AspectJ
#Retention(RetentionPolicy.RUNTIME)
public #interface GuiceInject {
Class<? extends AbstractModule> module();
}
Please try to redefine pointcut syntax as
Object around(): get(#package.subpackage.GuiceInject * *.*)
Correct field signature must specify the type of the field, the declaring type, and name. If your annotation is in different package, it should be fully qualified.

Java Spring DI not working with Java Configuration

I'm new to Java Spring and trying to use Java configuration and inject a dependency into a class constructor. I want to use constructor injection because the class methods require the dependency. It isn't working for me.
Use case: Create a JSON string from a Java object and validate it before returning.
Class: FakeJsonBuilder
Dependency: JsonValidator
Main class: Per Spring documentation the #SpringBootApplication annotation is a convenience annotation that adds #Configuration, #EnableAutoConfiguration and #ComponentScan so I should be good to go as far as dependency injection is concerned.
#SpringBootApplication
public class MySpringApplication {
public static void main(String[] args){
// Register the class we use for Java based configuration
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext();
context.register(ApplicationConfiguration.class);
context.refresh();
SpringApplication.run(MySpringApplication .class, args);
}
}
Java configuration class:
#Configuration
public class ApplicationConfiguration {
#Bean
public JsonValidator jsonValidator(){
return new JsonValidatorImpl();
}
#Bean
public JsonBuilder(){
return new FakeJsonBuilder();
}
}
FakeJsonBuilder class:
public class FakeJsonBuilder implements JsonBuilder{
private static Log logger = LogFactory.getLog(FakeJsonBuilder.class);
private static JsonValidator jsonValidator;
// I need an empty constructor for the ApplicationConfiguration setup to work.
public MlrModelJsonBuilder(){};
#Autowired
public FakeJsonBuilder (JsonValidator jsonValidator){
this.jsonValidator = jsonValidator;
boolean validatorInjected = (jsonValidator != null);
logger.info("Validator injected: " + validatorInjected);
}
.......... More methods
The jsonValidator dependency is not being injected, i.e. the log message is Validator injected: false
Quoting Martin: Fowler http://martinfowler.com/articles/injection.html
"My long running default with objects is as much as possible, to create valid objects at construction time. This advice goes back to Kent Beck's Smalltalk Best Practice Patterns: Constructor Method and Constructor Parameter Method. Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place. If there's more than one way to do it, create multiple constructors that show the different combinations."
I come from a .NET background and use Ninject to inject my dependencies into the class constructor for the reasons Fowler gives. I quoted Fowler because of his credibility but you will find many sources providing the same argument, i.e. if the class methods require the dependency then it should be injected into the constructor. So here's how I figured how to do it with Java Spring (I revert to my C# syntax - forgive the transgression):
The configuration class
#Configuration
public class ApplicationConfiguration {
#Bean
public IJsonValidator jsonValidator(){
return new JsonValidator();
}
#Bean
public IJsonBuilder jsonBuilder(){
return new JsonBuilder(jsonValidator());
}
}
The class into which we inject the dependency
public class JsonBuilder implements IJsonBuilder {
private static IJsonValidator _jsonValidator;
// #Autowired // not needed per Sotirios. tested and verified
public JsonBuilder(IJsonValidator jsonValidator) {
_jsonValidator = jsonValidator;
}
public String getFoobar() {
// Returns false. jsonValidator was injected
boolean foo = (_jsonValidator == null);
return "Validator was injected: " + foo;
}
... more methods

Categories

Resources