Spring Boot - Could not find a suitable constructor error - java

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.

Related

Spring not calling the default constructor

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

Spring Boot - how to get a class annotated with #Service by it's name

I'm quite new to spring (switching from PHP to Java).
In my code I have a java.lang.reflect.Method objects and I need to instantiate it's class with all it's dependencies.
Normally I'd use #Autowired annotation in my code, but it's not possible because my code gets different Method objects, not specific classes.
Question is - how to get a class instance from dependency container without using annotations and having just class name?
In php i used libraries which gave me access to container and I could just get DI services by it's class name just like:
$this->container->get('My\Class\Name');
In spring I tried:
#Autowired
private ApplicationContext context;
void myMethod(Method method){
this.context.getBean(method.getClass());
and
this.context.getBean(method.getClass().getName());
and that was resulting in NullPointerException.
EDIT
Thanks for quick replys,
I tried using
context.getBean(method.getDeclaringClass());
and
context.getBean(method.getDeclaringClass().getSimpleName());
And it both resulted in NullPointerException as well.
Actually it's okay for my needs to get that class by class or by name. I'm trying to write my own command bus for CQRS.
Let me show you some code:
Handler:
public class SimpleCommandBus implements CommandBus {
#Autowired
private ApplicationContext context;
private Map<Class, Method> registry = new HashMap<>();
#Override
public void register(Class c, Method o) {
registry.put(c, o);
}
#Override
public void dispatch(Object command) {
if (!registry.containsKey(command.getClass())) {
throw new CommandDispatchException(String.format("Handler for command %s was not defined.", command));
}
Method method = registry.get(command.getClass());
Object handler = context.getBean(method.getDeclaringClass().getSimpleName());//line causing exception
Service class:
#Service
public class TestHandler {
public void handle(TestCommand command){
System.err.println(command.getId());
}
}
Calling command bus:
Method method = TestHandler.class.getMethod("handle", TestCommand.class);
TestCommand command = new TestCommand("Test command");
commandBus.register(TestCommand.class, method);
commandBus.dispatch(command);
Use java.lang.reflect.Method.getDeclaringClass() to find in which class the given method is declared. method.getClass() will return the type of method object which is java.lang.reflect.Method.
#Autowired
AplicationContext ctx;
...
Object bean = ctx.getBean(method.getDeclaringClass());
In Spring the default name is the simple name.
Plus as in Karols answer you must use getDeclaringClass() to get the class of the class with the method.
So you must call
this.context.getBean(method.getDeclaringClass().getSimpleName());

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.

How to register a static class in Jersey?

I have a class of which only static methods are to be accessed via #path annotations and which does not have a public constructor. My simpilified program is:
#Path("")
static class MyStaticClass
{
private MyStaticClass() {...}
#Get #Path("time")
static public String time()
{
return Instant.now().toString();
}
}
Running and calling "time" gives me the following error:
WARNUNG: The following warnings have been detected: WARNING: HK2 service reification failed for [...] with an exception:
MultiException stack 1 of 2
java.lang.NoSuchMethodException: Could not find a suitable constructor in [...] class.
Sorry, according to the JSR, paragraph 3.1.2
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.
You can use the Adapter design pattern and create JAX-RS resource (POJO with #Path) which simply delegates to your static class. This would be very easy to understand for those coming behind you.
The #Path annotation is designed to define a resource at the class level. The method to execute isn't controlled by #Path, but by #GET, #POST, #PUT, #HEAD, etc... with #GET as the desired operation in your case.
Your class for the "time" resource should look like this:
#Path("/time")
public class TimeResource {
#GET
public static String time(){
return Instant.now().toString();
}
}
You could theoretically define each function as a static nested class within one "main" class:
public class MyResource{
#Path("/time")
public static final class TimeResource {
#GET
public static String do(){
return Instant.now().toString();
}
}
#Path("/doSomethingElse")
public static final class DoSomethingElseResource {
#GET
public static String do(){
// DO SOMETHING ELSE
}
}
}
Though I don't know if that would work, you'd have to try it. I don't think there's much advantage in having them all in one class like that, though.

Refactoring static class so I can unit test it

I have a static class that I would like to refactor so I can change the name of the properties file etc., and to be able to unit test it easier.
Current I have this:
public enum MySettings {
INSTANCE;
//priv vars
private string applicationUrl;
private MySettings() {
MappingJsonFactory jf = new MappingJsonFactory();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream mySettingsInputStream = classLoader.getResourceAsStream("a.properties");
Properties mySettingsProperties = new Properties().load(mySettingsInputStream);
// code below to load json and set priv vars etc.
}
public String getApplicationUrl() {
return applicationUrl;
}
}
How could I set the name of the properties file to something else in my unit tests?
"Inversion of control." The simplest way to do this here would be to take it in as a constructor arg. At the higher end would be an IOC framework, such as Spring.
Worse case since you're dealing with an enum - may need to factor out an interface then provide an implementing enum. Or better:
public enum Settings {
PRODUCTION("prod.xml"), UNIT_TESTING("dev.xml");
//...
you could fiddle all the stuff from the enum class into a real instantiable class (via package protection or protected) and then make an instance of it accessible via the enum (getter). Like this you can unit test everything like a charm and also have it as a singleton :). With this you don't need a second Enum constant (as pointed out in the comments).
If you are using protected instead of package protection you can unit test it by creating a dummy class that inherits from the actual class and instantiate it in the test like this:
private static class Dummy extends NewClass {
public Dummy() {
super();
}
}

Categories

Resources