Spring environment.getActiveProfiles(); is always null - spring

I have page in xhtml, I want to not render this page on production so I wrapped all elements on page with panel
<p:panel id="main" rendered="#{swaggerBean.activeProfiles}" >
SwaggerBean.class:
#ManagedBean
#ViewScoped
#Data
public class SwaggerBean{
#Autowired
Environment environment;
public boolean getActiveProfiles() {
String[] activeProfiles = environment.getActiveProfiles();
for (String activeProfile : activeProfiles) {
if (activeProfile.contains("prod"))
return true;
}
return false;
}
}
After I try to enter to my page I have null pointer exception on line:
String[] activeProfiles = environment.getActiveProfiles();
I also tried to inject Environment by #ManagedProperty, but result is the same
#ManagedProperty(value="#{environment}")
private Environment environment;
Do You know how to avoid this null pointer on my #ManagedBean?
I tried solution with EnvironmentAware from Autowired Environment is null, but still there's NPE, or maybe there's better way to disable my page on production?

Annotate SwaggerBean with #Component rather than #ManagedBean

Related

Spring #Value not working in Spring Boot 2.5.5, getting null values

I am trying to inject some property values into variables by means of Spring #Value annotation but I get null values. I tried different configurations and triks but it doesn't work. Think is that before today everythink was working properly. I do not know what I changed in order to get things broken.
Here is my java class:
#Component
#ConditionalOnProperty(prefix = "studioghibli", name = "get")
public class StudioGhibliRestService {
#Value("${studioghibli.basepath}")
private static String BASE_PATH;
#Value("${studioghibli.path}")
private static String PATH;
#Value("${studioghibli.protocol:http}")
private static String PROTOCOL;
#Value("${studioghibli.host}")
private static String HOST;
private static String BASE_URI = PROTOCOL.concat("://").concat(HOST).concat(BASE_PATH).concat(PATH);
#Autowired
StudioGhibliRestConnector connector;
public List<StudioGhibliFilmDTO> findAllFilms() throws SipadContenziosoInternalException {
var response = connector.doGet(BASE_URI, null, null);
if (!response.getStatusCode().is2xxSuccessful() || !response.hasBody()) {
throw new SipadContenziosoInternalException(Errore.INTERNAL_REST_ERROR, "FindAll(), microservizio ".concat(BASE_URI), null);
}
return (List<StudioGhibliFilmDTO>) response.getBody();
}
}
As you can see, the class is annotated with #Component, that because I will need to use it as #Service layer in order to make a rest call in my business logic.
The class is also annotaded with conditional on property...
Here is a screenshot of the debug window at startup:
Since the PROTOCOL value is null, i get a null pointer exception immediately at start up.
Here is part of the application-dev.properties file:
studioghibli.get
studioghibli.protocol=https
studioghibli.host=ghibliapi.herokuapp.com
studioghibli.basepath=/
studioghibli.path=/films
First of all, #Value annotation does not work with static fields.
Secondly, fields with #Value annotation is processed when the instance of the class (a bean) is created by Spring, but static fields exist for a class (for any instance), so when the compiler is trying to define your static BASE_URI field other fields are not defined yet, so you get the NPE on startup.
So you might need a refactoring, try to inject values with the constructor like this:
#Component
#ConditionalOnProperty(prefix = "studioghibli", name = "get")
public class StudioGhibliRestService {
private final StudioGhibliRestConnector connector;
private final String baseUri;
public StudioGhibliRestService(StudioGhibliRestConnector connector,
#Value("${studioghibli.basepath}") String basePath,
#Value("${studioghibli.path}") String path,
#Value("${studioghibli.protocol:http}") String protocol,
#Value("${studioghibli.host}") String host) {
this.connector = connector;
this.baseUri = protocol.concat("://").concat(host).concat(basePath).concat(path);
}
// other code
}
Thanks, It works for me, I have to add some codes to my project. Then I check the spring core document in "#Value" section. Besides
When configuring a PropertySourcesPlaceholderConfigurer using
JavaConfig, the #Bean method must be static.
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}

How to get a boolean variable DEBUG in a Thymeleaf?

How to find out if a project is in debug mode and get a variable of a logical type in the thymeleaf template.
<h1 th:if="${DEBUG}">...</h1>
You can achieve this while injecting the Environment bean to your contorller:
#Controller
#RequestMapping("/public")
public class PublicController {
private final Environment environment;
public PublicController(Environment environment) {
this.environment = environment;
}
#GetMapping("/debug")
public String returnFoo(Model model) {
String envValue = environment.getProperty("debug");
boolean isDebugMode = (envValue != null && !envValue.equals("false"));
model.addAttribute("DEBUG", isDebugMode);
System.out.println(isDebugMode);
return "yourView";
}
}
This is implementation is working for every possible way you might set the debug flag to your application (How can I tell whether my Spring boot application is in debug mode?)

How to mock beans Autowired on service layer in #WebMvcTest

I am testing a REST API's in Spring boot gradle app, my mocked service using #MockBean is returning null. This mocked service return null if there are some beans Autowired in service class(I used constructor injection).
Here is sample Code(Not compiled, only for understanding)
#RestController
#RequestMapping("/xxx")
class TestController {
private RetriveDataService retriveDataService;
public TestControllerx(RetriveDataService retriveDataService) {
this.retriveDataService = retriveDataService;
}
#PostMapping(value = "/yyy")
public MyResponseModel myMethod(#RequestBody MyRequestModel model) {
return retriveDataService.retriveData(model);
}
}
#Service
class RetriveDataService {
private TokenService tokenService;
public RetriveDataService(TokenService tokenService) {
this.tokenService = tokenService;
}
public MyResponseModel retriveData(MyRequestModel model) {
String accessToken = tokenService.getToken().getAccessToken();
return retriveData(model, accessToken);
}
}
#RunWith(SpringRunner.class)
#WebMvcTest(TestController.class)
public class TestControllerTest {
#Autowired
private MockMvc mvc;
#Autowired
private ObjectMapper objectMapper;
#MockBean
private RetriveDataService retriveDataService;
#Test
public void testRetriveData() throws Exception {
mvc.perform(MockMvcRequestBuilders.post("/xxx/yyy").content(objectMapper.writeValueAsString(new MyRequestModel()))
.contentType(MediaType.APPLICATION_JSON_UTF8)).andDo(MockMvcResultHandlers.print())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
}
}
When I run this test, i am getting following output(If my service do not need another bean, I am getting expected output)
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Due to this response i facing problem on line .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));. also when i check response body(as body is also a null)
Sample project to reproduce the issue is here
Checking your repository confirmed assumption form the discussion in comments under question.
You specify expectations on your mock
MyModel requestMessage = new MyModel();
requestMessage.setMessage("Hello Request Post");
given(testService1.getMessage(requestMessage)).willReturn(responseMessage);
but the message received to in your controller in your #WebMvcTest is not equal to requestMessage specified in the test. This is due to the fact that MyModel class does not override equals method.
In this situation, Mockito will use its default behaviour:
By default, for all methods that return a value, a mock will return either null, a primitive/primitive wrapper value, or an empty collection, as appropriate. For example 0 for an int/Integer and false for a boolean/Boolean.
You have two options to fix the problem:
override equals (and hashCode) in your request class.
Get acquainted with argument matchers
More info on option 2.:
Technically, your expectation is equivalent to:
given(testService1.getMessage(ArgumentMatchers.eq(requestMessage)))
.willReturn(responseMessage);
You can use other matcher, or even define your own. This is useful if you cannot modify code of your argument's type (type coming from 3-rd party library etc).
For example, you can use ArgumentMatchers.any(MyModel.class))

store a form field value in session and get it as need on multiple pages

I have a JSF form in which there is one field(textfield), value in textfield say profileId, which I need to use in many pages, so how can we store it in a session, and also how can we retrieve it as we need?
In simple words set a variable value in JSF session and also get it.
Bind it to a session scoped managed bean.
#ManagedBean
#SessionScoped
public class Profile {
private Long id;
// ...
}
with
<h:inputText value="#{profile.id}" />
You can access it in other beans by injecting it as #ManagedProperty.
#ManagedBean
#ViewScoped
public class OtherBean {
#ManagedProperty("#{profile}")
private Profile profile;
public void submit() {
System.out.println(profile.getId());
}
// ...
}

IllegalStateException when trying to .getSessionMap() from a Session Scoped Bean

I'm new to Java and JSF. I need help with an IllegalStateException. Here's the scenario:
In my current project i have this Session Scoped bean for the application menu:
public final class MenuBean implements Serializable{
private MenuModel model;
private FacesContext context = FacesContext.getCurrentInstance();
public MenuModel getModel() {
return model;
}
public MenuBean() {
updateMenu();
}
public void updateMenu(){
Map session = (Map<String,Object>) context.getExternalContext().getSessionMap();
EUser user = (EUser) session.get(UserBean.USER_SESSION_KEY);
...
}
private MethodExpression createMethodExpression(String action) {
...
}
}
At some point of my logic, i need to update the menu, so i do this:
ExternalContext extContext = context.getExternalContext();
Map sMap = (Map<String,Object>) extContext.getSessionMap();
MenuBean menu = (MenuBean) sMap.get("menuBean");
menu.updateMenu();
The bean constructs fine, but when i try to manually update it as shown above, i get and IllegalStateException on the 1st line of the update method updateMenu()
I don't understand what's wrong, since I can get the session map with that same call whe the menu is build in the first time.
Also, using the NetBeans debugger, i can see that the instance of MenuBean is correctly recovered.
Can you guys help me?
The FacesContext is stored in the HTTP request thread. You should absolutely not declare and assign it as an instance variable of an instance which lives longer than the HTTP request (and preferably also just not when it's already request based -it's bad design). The FacesContext instance is released and invalidated when the HTTP request finishes. In any subsequent HTTP request the instance is not valid anymore. There's means of an illegal state. That explains the IllegalStateException you're seeing.
You need to remove the following line:
private FacesContext context = FacesContext.getCurrentInstance();
And fix your code to get it only threadlocal in the method block:
Map<String, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
// ...
You can always assign it as a variable, but that should only be kept threadlocal:
FacesContext context = FacesContext.getCurrentInstance();
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
// ...
Unrelated to the concrete problem, using #ManagedProperty has been easier in this particular case.
public final class MenuBean implements Serializable {
#ManagedProperty("#{user}")
private EUser user;
// ...
}
JSF will then inject it for you.

Resources