users@javaserverfaces-spec-public.java.net

[jsr344-experts mirror] Re: JSF MVC?

From: Adrian Gonzalez <adr_gonzalez_at_yahoo.fr>
Date: Sat, 1 Mar 2014 20:57:50 +0000 (GMT)

Hello,


> do you think this is the way forward for JSF?

I don't know if this is the way forward for JSF or JAX-RS.

But HTML5/JS and REST services being the hype of today, I don't know if there's many users interested in an action-based framework (even if IMO it's usefull to have this choice - being able to build simple applications with a simple technology ;) ).

Both JAX-RS and JSF miss some features for a MVC framework.
JSF misses (at least) the following stuff to support reasonably well the MVC scenario :
 1. it doesn't support for now HTTP REST usage : HTTP PUT, POST (without postback), DELETE, etc...
   This is a blocker. 
 2. templating : plugging in a 3rd party templating engine easily should be supported in MVC. 
   ASP.NET MVC supports this kind of pluggability (see http://stackoverflow.com/questions/1451319/asp-net-mvc-view-engine-comparison).
  I'm not sure if plugging another templating engine with JSF is easy.
  Of course, facelets and JSP should be supported out ot the box. 
   With this extensibility point, we could in the future have something like Play templating or ASP.NET MVC Razor templating.

> I thus wonder what everyone's opinion is about this prototype Manfred created.

Personnally, I would have expected to use JAX-RS as a starting point for an action based framework.
If JSF is used as a base for an MVC framework, it would need to duplicate JAX-RS @Path @PathParam, @HttpMethod, @GET, @POST, ... 
It would be nice to be able to use those same annotations for MVC and REST usage (i.e. in theory, using @Consumes should be enough to differenciate 2 methods

mapped to the same URI and the same HTTP verb).

Another point is that Spring MVC annotations handle REST and MVC usage. Same thing for Play.
So unifying a REST and an action framework has already been done successfully. 
This is not the case for a component and an action based framework.
As I recall, Spring MVC has been built after JAX-RS. Spring MVC authors didn't used JAX-RS because it was too limiting for them .
Perhaps someone should ask them why JAX-RS was too limiting in order to lift those limitations ?

As for PlayFramework, I didn't used it, but here are some goodies : 

 * code reloading - a must have !
 * view are compiled so you can use them in the controllers (to populate the view and to navigate to them).
 * view templates (and form helpers) are more succinct/understandable than the same in JSP / facelets.

Some experimentations related to MVC usage :
 * CDI and MVC : http://www.andygibson.net/blog/article/implementing-spring-mvc-with-cdi-and-java-ee-6/
 * JAX-RS and templating engine : https://jersey.java.net/documentation/latest/mvc.html

The two sample below show how I used Spring MVC to implement an action-based controller [1] and a REST backend [2] - just to give an idea of how the same annotations are used in those 2 cases..  

From what I recall, using ASP.NET MVC 3 was similar to Spring MVC (ASP.Net APIs were a bit inferior on the controller side, but Razor templating was far superior to JSP).

Best regards,
Adrian

[1] An action-based controller with Spring MVC 
@Controller
@RequestMapping(value = "/exemple/clients")
public class ClientController {
@Inject
private ClientManager clientManager;

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String show(@PathVariable Long id, Model uiModel) {
Client lClient = clientManager.findById(id);
uiModel.addAttribute(lClient);
uiModel.addAttribute("itemId", id);
return "exemple/client/show";
}

@RequestMapping(method = RequestMethod.POST)
public String create(@Valid Client client, BindingResult bindingResult,
Model uiModel) {
String inputView = "exemple/client/edit";
if (bindingResult.hasErrors()) {
return inputView;
}
client.setDateContact(new Date());
try {
clientManager.create(client);
} catch (SomeBusinessException e) {
bindingResult.reject("error.global", e.getMessage());
return inputView;
}
uiModel.asMap().clear();
return "redirect:/exemple/clients/" + client.getId();
}

@RequestMapping(params = "form", method = RequestMethod.GET)
public String createForm(Model uiModel, SitePreference sitePreference) {
uiModel.addAttribute(newClient());
return "exemple/client/edit";
}
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public String delete(@PathVariable Long id, Model uiModel, SitePreference sitePreference) {
Client client = clientManager.findById(id);
clientManager.delete(client);
uiModel.asMap().clear();
return "redirect:/exemple/clients" + (sitePreference.isMobile() ? "-mobile" : "");
}
@RequestMapping(method = RequestMethod.PUT)
public String update( @Valid Client client, BindingResult bindingResult,Model uiModel) {
String inputView = "exemple/client/edit";
if (bindingResult.hasErrors()) {
return inputView;
}
try {
clientManager.update(client);
} catch (MatriculeExistantException e) {
bindingResult.reject("error.global", e.getMessage());
return inputView;
}
uiModel.asMap().clear();
return "redirect:/exemple/clients/" + client.getId();
}

@RequestMapping(value = "/{id}", params = "form", method = RequestMethod.GET)
public String updateForm(@PathVariable Long id, Model uiModel) {
show(id, uiModel);
return "exemple/client/edit";
}

@RequestMapping(method = RequestMethod.GET)
public String list(@Valid ClientCriteriaForm clientCriteriaForm,
BindingResult aBindingResult,
Model uiModel) {
if (aBindingResult.hasErrors()) {
return "exemple/client/list";
}
...call clientManager...
uiModel.addAttribute("clients", clients);
return "exemple/client/list";
}

@RequestMapping(params = "list", method = RequestMethod.GET)
public String listForm(ClientCriteriaForm clientCriteriaForm, Model uiModel) {
List<Client> clients = new ArrayList<Client>();
uiModel.addAttribute("clients", clients);
return "exemple/client/list";
}
@RequestMapping(params="cancel")
public String cancel() {
return "redirect:/exemple/clients";
}
}

[2] A REST backend controller with Spring MVC 
@Controller
@RequestMapping(value = "/exemple/rest/clients")
public class RestClientController {

@Inject
private ClientManager clientManager;


@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public Map<String, Object> list(@Valid  ClientCriteriaForm clientCriteriaForm) {
List<Client> clients = clientManager.findByName(
clientCriteriaForm.getNom(), clientCriteriaForm.getPage()
* clientCriteriaForm.getSize(),
clientCriteriaForm.getSize() + 1);
Map<String, Object> lResults = new HashMap<String, Object>();
if (clients.size() > clientCriteriaForm.getSize()) {
lResults.put("hasNextPage", true);
lResults.put("page", clientCriteriaForm.getPage());
clients.Remove(clientCriteriaForm.getSize().intValue());
}
lResults.put("clients", clients);
return lResults;
}

@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces="application/json")
@ResponseBody
public Client show(@PathVariable Long id) {
return clientManager.findById(id);
}
@RequestMapping( method = RequestMethod.POST, produces="application/json")
@ResponseBody
public Client create(@RequestBody @Valid Client client) throws SomeBusinessException {
return clientManager.create(client);
}
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces="application/json")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long id) {
Client client = clientManager.findById(id);
clientManager.delete(client);
}

@RequestMapping(method = RequestMethod.PUT, produces="application/json")
@ResponseBody
public Client update(@RequestBody @Valid Client client) throws SomeBusinessException {
return clientManager.update(client);
}
@ExceptionHandler(RequestBodyNotValidException.class)
@ResponseBody
public Map<String,Object> handleException(RequestBodyNotValidException exception, HttpServletResponse response) throws IOException {
  return RestUtils.convertAndSetStatus(exception, response);
}
@ExceptionHandler(Exception.class)
@ResponseBody
public Map<String,Object> handleException(Exception exception, HttpServletResponse response) throws IOException {
  return RestUtils.convertAndSetStatus(aException, aResponse);
}
}



________________________________
 De : arjan tijms <arjan.tijms_at_gmail.com>
À : users_at_javaserverfaces-spec-public.java.net
Envoyé le : Vendredi 28 février 2014 23h14
Objet : [jsr344-experts mirror] JSF MVC?
 


Hi there,

Many of you have undoubtedly read Manfred's blog about the action based prototype in Mojarra. For those who haven't yet, it's at https://weblogs.java.net/blog/mriem/archive/2014/01/13/jsf-tip-56-using-action-based-prototype-mojarra

This very same prototype is now also referred to as one of the 3 possible options in part 3 of the Java EE 8 survey concerning "An additional web MVC framework".

From the previous part of the survey it became clear that people are interested in the action based topic, but that there's no clear consensus whether this should be an upgraded JAX-RS, the standardization of Spring MVC or something else. That something else might thus just as well be an upgraded JSF (as I argued for last year here: https://java.net/projects/javaee-spec/lists/users/archive/2013-10/message/5)

I thus wonder what everyone's opinion is about this prototype Manfred created.

Clearly it's a prototype. Things like parameter injection have not been added yet and some (core?) details like how to exactly identify request parameters submitted by existing components have not been entirely fleshed out yet.

But, do you think this is the way forward for JSF?

Kind regards,
Arjan Tijms