Spring multiple #ModelAttribute methods in the same #Controller - forms

I have a page with two different forms (with two different submits) on Spring MVC 3, and I have a problem with #ModelAttribute methods. When I have two on the same controller, they are not always executed making the model to be NULL.
The code:
#Controller
#RequestMapping(value = "/session/admin/permission/{userId}")
public class PermissionController {
#Autowired
private UserManager userManager;
#ModelAttribute("passwordValidation")
private PasswordValidation getPasswordModel(){
return new PasswordValidation();
}
#ModelAttribute("user")
private User getUserModel(#PathVariable("userId") String userId){
//This is not executed
return userManager.getUser(userId);
}
#ModelAttribute("permissionsAvailable")
private PermissionsAvailable getPermissionsModel(#ModelAttribute("user") User user) {
return new PermissionsAvailable();
}
#RequestMapping(method = RequestMethod.GET)
public String adminPermission(){
return "/security/permission";
}
#RequestMapping(method = RequestMethod.POST, params="changeRoles")
public String modifyPermission(#ModelAttribute("permissionsAvailable") PermissionsAvailable permissions,
HttpServletRequest request, #ModelAttribute("user") User user,
final RedirectAttributes redirectAttributes){
//Modify something
}
#RequestMapping(method = RequestMethod.POST, params="changePassword")
public String modifyPassword(
#ModelAttribute("passwordValidation") PasswordValidation passwordValidation,
#ModelAttribute("user") User user,
HttpServletRequest request, BindingResult bindingResult,
final RedirectAttributes redirectAttributes){
return "newpage";
}
}
Don't know why, sometimes everything goes ok and every method is executed, but sometimes they are not executed.
UPDATE: I have two different controllers with the same problem so it must be an error on Spring or something I'm doing wrong.
Thanks.

The documentation doesn't mention anywhere that it's possible to use #ModelAttribute on an argument to a #ModelAttribute annotated method, like you're doing in your "getPermissionsModel()" method. It's possible that's not supported, since it's not documented as being supported. You might want to try either removing the "#ModelAttribute("user") User user" argument from your "getPermissionsModel()" method, and/or instead try just using one #ModelAttribute method to set all your model attributes:
#ModelAttribute
public void setAttributes(#PathVariable("userId") String userId, Model model) {
model.addAttribute(new PasswordValidation());
model.addAttribute(userManager.getUser(userId));
model.addAttribute(new PermissionsAvailable());
}

Related

How to get a JSF application scoped bean from webservice?

I have a jsf 2.0 application without Spring and I have implemented a cache as application scope which should be accessed from a Rest service. Now I would like to call the rest webservice which should check the cache, but when I want access it, it is always null.
I tried already Accessing FacesContext from Web Service and this one https://www.mkyong.com/jsf2/how-to-get-servletcontext-in-jsf-2/ , but it doesn't work for me.
#ManagedBean(eager=true)
#ApplicationScoped
public class CacheController implements Serializable{
private static final long serialVersionUID = 123L;
private Map<String, Cache> map = new HashMap<String, Cache>();
public Map<String, Cache> getMap() {
return map;
}
public void setMap(Map<String, Cache> map) {
this.map = map;
}
}
#Path("/service")
public class RestService {
#POST
#Path("anlieferung/kennzahlen")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String getValueFromCache(String item) throws JSONException, ParseException {
//is always null
CacheController cacheController= (CacheController) getServletContext().getAttribute("cacheController");
//is always null
FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
CacheController cacheBean = application.evaluateExpressionGet(context, "#{cacheController}", CacheController.class);
//doSomeStuff and check if the item is in the Cache (CacheController.getMap())
}
}
I have initialised the cache before over the jsf application and it works. Now I would expected that I get the Cache Object through the FacesContent or ServletContext, but it is always null. Do I need to create something like a ServletListener? Can somebody give me an example? Thank you

Content Type Not Set Junit REST POST test

I have a Spring Boot REST application. The unit tests for all of the GET requests are working perfectly; however, the POST requests are all returning
java.lang.AssertionError: Content type not set
Here is the controller:
#RestController
public class ClassificationController {
private IClassificationService classificationService;
#Autowired
public ClassificationController(IClassificationService classificationService) {
this.classificationService = classificationService;
}
#RequestMapping(value="/category", method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public CategoryDTO createCategory(#RequestBody final CategoryDTO category) throws MctException {
return classificationService.createCategory(category);
}
The unit test I have is:
#RunWith(MockitoJUnitRunner.class)
public class ClassificationControllerTest {
#Mock
private IClassificationService classificationService;
#Before
public void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(new ClassificationController(classificationService)).build();
}
#Test
public void createCategoryTest() throws Exception {
String jsonTask = String.format("{\"id\": \"2\",\"categoryName\": \"Category Name 2\"}");
MvcResult result = mockMvc.perform(post("/category")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(jsonTask))
.andDo(MockMvcResultHandlers.print())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(content().string(containsString("\"id\":2")))
.andExpect(content().string(containsString("\"categoryName\":\"Category Name 2\"")))
.andExpect(status().isCreated())
.andReturn();
}
I have also tried this with a CategoryDTO object instead of the String jsonTask with the same result.
I discovered it was just failing on that assertion because it was the first one, but it just wasn't returning anything from the endpoint. I am returning the content type because it is returning the object that is being inserted so a content type is valid. I ended up changing my test create the content JSON using an ObjectMapper and then I had to add an equals method on my domain object....once I added the equals method, the test passed. I didn't realize the mock framework used that method.
#Test
public void createClassTest() throws Exception {
String jsonInString = objectMapper.writeValueAsString(singleClass);
when(classificationService.createClass(5, singleClass)).thenReturn(singleClass);
MvcResult result = mockMvc.perform(post("/class/5")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(jsonInString))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(content().string(containsString("\"id\":1")))
.andExpect(content().string(containsString("\"className\":\"Test Class Name 1\"")))
.andExpect(status().isCreated())
.andReturn();
verify(classificationService).createClass(5, singleClass);
}
Judging by the assertion error, it seems the endpoint is not returning a MediaType.APPLICATION_JSON_UTF8. Try removing the contentType check or debugging and seeing what the endpoint is actually returning. Once again, judging by the error you are seeing, seems it's not returning any content type at all. So you should probably be checking that no content type is set.
I know typically the POST request I usually test do not return a contentType at all.
After all, it could be that endpoint is actually doing something incorrectly if you do expect the content type to be set.

Spring Rest API, receiving one or list of object using same URL

I want to insert one or list of object using same URL :
#RequestMapping(value = "/subject", method = RequestMethod.POST)
public #ResponseBody void addSubject(#ModelAttricbute Subject subject){
... // Inserting a subject
}
#RequestMapping(value = "/subject", method = RequestMethod.POST)
public #ResponseBody void addSubject(#RequestBody Subject[] subject){
... // Inserting all the subject in the array
}
I want to be able to do those 2 things without changing the URL of Request.
Thanks in advance

Spring Data Rest CrudRepository vs ReadOnlyRepository

I noticed an anomaly in the way Spring Data Rest repositories are behaving. I have two types of entities. in my application - readonly entities (for reference data like statecodes, country codes, zip codes etc.). I don't want to let the end user change these. So I implemented the following ReadOnly repository.
#NoRepositoryBean
public interface ReadOnlyRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
Iterable<T> findAll();
}
#Repository
public interface StateRepository extends ReadOnlyRepository<State, Long> {
}
Now, all other entities have CrudRepositories associated with them because they are editable entities like addresses which reference the states and zip codes.
Here's an example.
#Repository
public interface CustomerRepository extends CrudRepository<Address, Long> {
}
I have a controller for both readonly and editable entities, with a pass-through call to the repositories.
#RestController
#RequestMapping(value = "/addresses", produces = MediaType.APPLICATION_JSON_VALUE)
public class AddressController {
#Autowired
private AddressRepository addressRepository;
#RequestMapping(method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public Iterable<Address> getAllAddresses() {
return addressRepository.findAll();
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public Address getAddress(#PathVariable("id") Long id) {
return addressRepository.findOne(id);
}
}
I have an identical Controller corresponding to the State entity.
Funnily enough, the request to StateController gives me a HATEOAS json response, while the request to Address gives me a non HATEOAS json response. What gives?
My bad. My application server did not redeploy certain repositories. This is a non-issue.
So for those running into these issues, you are likely using hot-code replace feature of your IDE. Consider restarting your app and it should be a non-issue.

Redirecting from one method to another in a same controller in Spring MVC 3.0

I have a user controller. It has three methods for listing users, showing a user add page and saving a user. When the user is saved, it should redirect to the user listing page.
In my case when I try to do the redirect, I am getting the following error.
No mapping found for HTTP request with URI [/myApp/cases/cases] in DispatcherServlet
Below is my entire UserController.
#Controller
#RequestMapping("/users")
public class UserController extends BaseController {
private static Logger logger = Logger.getLogger(userController.class);
#RequestMapping(method = RequestMethod.GET)
public ModelAndView list() {
logger.info(" [list] - showing user list.");
ModelAndView mav = new ModelAndView("userList");
mav.addObject("users", new ArrayList<User>());
return mav;
}
#RequestMapping(value = "/new", method = RequestMethod.GET)
public ModelAndView form() {
logger.info(" [form] - showing new user creation form.");
ModelAndView mav = new ModelAndView("userForm");
mav.addObject("user", new User());
return mav;
}
#RequestMapping(method = RequestMethod.POST)
public String save(User user) {
logger.info(" [save] - saving user.");
return "redirect:/users";
}
}
Am I doing the redirection proper way?
Add the context of DispatrcherServlet. For example, if URL pattern of dispatcher servlet (in web.xml) is 'myApp' then it should be: return "redirect:/myApp/users";