Spring MVC why my property is null when invoke an #Value property - spring-mvc

My code as following:
public class BgpService{
#Value("${serviceName}")
private String serviceName;
private String fullName = serviceName+"/rest"
}
I do have serviceName in my config.properties file, the value is serviceName=10.1.1.1, But when I use fullName the value is null/rest, I expected it should be 10.1.1.1/rest.

Couple of things you need to check & fix in your code.
From your given snippet you are missing the #Component & #Configuration & #PropertySource annotation
#Component
#Configuration
#PropertySource("classpath:config.properties")
public class BgpService{}
You are trying to assign/use the value of serviceName field on static level (class) hence you need to define the field serviceName as static.
#Value("${serviceName}")
private static String serviceName;
And add a post construct method in order to assign value to another field. Currently your initialisation is invalid.
#PostConstruct
public void init(){
fullName = serviceName+"/rest"
}

Is your class "BgpService" considered as a spring bean? Do you have any spring annotation above it (e.g. #Service or #Component)? Is this class within the "component scan" range? Properties are injected by Spring to Spring beans only.
Can you access other properties from your config file from another class? This will show if your property file is within a classpath.

Related

Please help to explain a strange combination of Lombok's #AllArgsConstructor and spring's #RestController

I'm working on a spring project from our customer.
Below is the code for controller
#Log4j2
#RestController
#AllArgsConstructor
#RequestMapping(path = "/api/theapi")
#Api(value = "Description for the API")
public class TheAPIController {
private final ModelMapper modelMapper;
private final ObjectMapper objectMapper;
private final TheDemoService demoService;
...other code for controller
}
Below is the code for Service:
#Service
public class TheDemoService{ ... }
I was so surprise about 2 things:
Question 1: Why we need to use #AllArgsConstructor from project Lombok?
As per my understanding, Spring provide #RestController that Spring runtime container will initialize an Instance for our Controller. So that, having a constructor for our Controller seems like an invalid approach for using Spring Inversion of Control, is this correct?
Question 2. Because of using #AllArgsConstructor, somehow, the instance for demoService is to be injected
But again, I surprise because the code of Controller does not have #Autowired in combine with demoService.
In the actual code, there is no #Autowired for "private final TheDemoService demoService".
Hence, I could think of a possibility there, is that because of Lombok's #AllArgsConstructor would inject an instance of our TheDemoService via a constructor of
TheAPIController, I could not reason anything about this logic.
It's Invalid approach, no need for defining constructor for RestController
It's implicitly auto wiring the service
if a class, which is configured as a Spring bean, has only one constructor, the Autowired annotation can be omitted and Spring will use that constructor and inject all necessary dependencies.
To sum up #AllArgsConstructor can/should be removed

Using a custom interceptor in spring-boot, the #Value default is taking precedence over my configured value

I am in the trenches of writing my first spring-boot app, so I believe I have a configuration issue somewhere that is causing my error.
I have a class, "MyInterceptor", and it is annotated with "#Component" and extending HandlerInterceptorAdapter.
#Component
public class MyInterceptor extends HandlerInterceptorAdapter { ... }
And I have a configuration class "WebConfiguration" that is annotated with "#Configuration" (and is NOT annotated with "#EnableWebMvc").
I declare/inject my interceptor class in WebConfiguration like so:
#Resource
private MyInterceptor myInterceptor;
and then specify this class as an interceptor like so:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor);
}
In MyInterceptor, I have a property declared for which I want to inject a value. I have it declared, with a default, like so:
#Value("${my.interceptor.property:default_value}")
private String myInterceptorProperty;
When I have the "default_value" declared in the #Value annotation as I do above, then that value is always used. The value declared in my application-dev.yml file is ignored.
When I remove the default value, then the value in my application-dev.yml is used.
It is my suspicion that the default value from the #Value annotation is being loaded AFTER the configured value and overriding it for some reason. But I can't figure out why or how to stop it.
Other services in my app that are using #Value annotations, but that are NOT declared/injected in my WebConfiguration, are not exhibiting the same behavior.
I tried adding my interceptor like this instead:
#Bean
public MyInterceptor getMyInterceptor() {
return new MyInterceptor();
}
and then changed this:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getMyInterceptor());
}
But when I did this, then the configuration values in the application-dev.yml were never picked up regardless of whether or not I had a default value declared.
I do understand why the #Resource annotated injection is making my configured properties available, and why the direct constructor call in the Config class is not. But is using the #Resource annotation the wrong way to do it? Why isn't my default being overridden?
How should I be injecting configuration values into my interceptors and other classes that are similarly declared in my Config class?

Custom class level bean validation constraint

I already know how to add annotation based validation on specific attributes in Entity class like :-
public class Person {
#NotNull
private String firstName;
private String lastName;
//...
}
But is it possible to add annotation on class Person, in order to validate all the attributes inside this class, by creating a Customised Validation Class and handling validation there somewhere like :-
#Retention(value = RetentionPolicy.RUNTIME)
#Target(value = ElementType.METHOD)
public #interface PersonneName {
public String firstName();
}
I am working on a project to get Constraints from Database and creating Customised Validation Class and applying on the Entity class attributes according to the constaints got from DB.
Please suggest.
Yes, of course, it's possible. First, create the definition of your annotation. Pretty much like you did in your example, however, with a different #Target type
#Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = PersonValidator.class)
public #interface ValidPerson {
String message () default "Your custom message";
Class<?>[] groups () default {};
Class<? extends Payload>[] payload () default {};
}
Then implement the validator whose isValid method takes the instance of your Person class:
public class PersonValidator implements ConstraintValidator<ValidPerson, Person> {
#Override
public boolean isValid (Person person, ConstraintValidatorContext context) {
// your validation logic
}
}
Sure it is possible, just check the documentation regarding how to write custom class level constraints - http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-class-level-constraints
The important thing of course is that you make sure that one can actually place the constraint annotation on the type level. For that you need to add ElementType.TYPE to the #Target annotation.

How can I use same EJB in two different CDI beans and retrieve the values set from one bean into the another?

I have a stateful session bean where a list is maintained:
#Stateful
public class CartDAO{
private List<ShoppingCart> tempCart;
public void add(ShoppingCart shoppingCart){
tempCart.add(shoppingCart);
}
public List<ShoppingCart> getCart(){
return tempCart;
}
#PostConstruct
public void init(){
tempCart = new ArrayList<>();
}
}
Controller1 to add to the cart:
#Named
#SessionScoped
public class Controller1 implements Serializable {
#EJB
CartDAO cartDao;
public String addToShoppingCart() {
cartDao.add(shoppingCart);
}
}
Now, i want to ask you could i get the added items to the list from another cart?
#Named
#SessionScoped
public class Controller2 implements Serializable {
#EJB
CartDAO cartDao;
public String getShoppingCart() {
System.out.println(cartDao.getCart());//returns null
}
}
Obviously the above code returns null.
How do I retrieve the list from another controller. Any help will be much appreciated.
I don't see any obvious mistake here (are you sure that you don't call Controller2#getShoppingCart() before adding any items do your CartDAO?) but here are couple of my notions
you should have your CartDAO implement some interface or make it #LocalBean
all stateful beans should have method annotated with #Remove so you can clean the resources used in the bean (close datasources and son) and bean will be removed from the memory after this call
now it's recommended to use #Inject everywhere instead of #EJB, it's the same (you have to use #EJB only when you inject remote beans)
And also one point, if the System.out.println(cartDao.getCart()); returns null than it means the #PostConstruct haven't been called which is strange. Can you provide some more info about container and your environment?Also show us imports, this is big source of mistakes.

How do I Autowire some beans to be automatically injected with Spring MVC 3?

OK, so we are learning Spring MVC 3. And we are a little new to IoC, DI, etc. We want to clean up a lot of our old legacy mistakes. :-)
We are really liking #Autowired for our user services, etc.
However, we now have an issue that we would like to solve with Autowiring.
Let's say we have a Login bean:
public class Login {
private String username;
private String email;
// getters/setters....
}
This bean should be used session wide. We want every controller to be able to access this single object.
Which I'm assuming we need in our application-config.xml
<bean id="login" class="com.example.models.Login" scope="session" />
Also, let's say we have another class as:
public class Employee {
private String firstName;
private String lastName;
private Login login;
public Employee(Login paLogin) {
this.login = paLogin;
}
}
And to put that in session:
<bean id="employee" class="com.example.models.Employee" scope="session" />
OK, later on in our application, we have an email notification service. That service needs to access the username and email from the Login bean AND information from the Employee bean. Granted I could access the login bean from session memory but this is just an example.
#Controller
public class EmailController {
#Autowired
Login login; // this should come from session memory automatically right??
#Autowired
Employee employee; // OK, this should also come from session memory. Which contains a reference of the login too. Correct?
// getters/setters....
public void sendEmails() {
// ....
String email = login.getEmail();
String firstName = employee.getFirstName();
// ....
}
}
I hope this makes sense. What we are really wanting to accomplish is reducing XML configs, reducing constant parameter passing, minimal annotations, etc.
Any help that could point me in the right direction would be appreciated.
Thanks!
Couple of things about the controller you have put up.
#Controller
public class EmailController {
#Autowired
Login login; // The container has to create a bean of type Login to autowire into EmailController
#Autowired
Employee employee; //same as above
// getters/setters....
}
If the container has to create a singleton bean on application startup, you have to mark the Login and Employee class with annotation #Component.
Even annotations like #Repository, #Service does this. You can have look at this answer for difference between these annotations.
So once you mark your classes with any of these annotations, singleton beans of respective type will be created on application startup. You will see something like this in your logs
Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#6c811e18
And then a list of beans it has created. You can inject these beans to other beans. And these beans aren't stored in the session. But they are managed by the container itself.
You can do away with the xml bean definitions if your are using annotations like #Controller, #Component etc. Also you can avoid majority of your xml configuration files by using #Configuration. You can check here and here for examples.

Resources