Announcement Announcement Module
Collapse
No announcement yet.
With the Jackson library in the application classpath MVC still uses flexjson Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • With the Jackson library in the application classpath MVC still uses flexjson

    The docs: http://www.springsource.org/roo/guide?w=base-json
    state that:
    Option 2:
    Spring MVC detects the Jackson library in the application classpath

    However it appears that that is not the case.

    With these files in my current dir:
    jackson-core-asl-1.8.4.jar
    jackson-jaxrs-1.8.4.jar
    jackson-mapper-asl-1.8.4.jar
    and CLASSPATH-./

    I'm still getting serialisers that import flexjson:

    import flexjson.JSONDeserializer;
    import flexjson.JSONSerializer;

    and include the same 4 flexjson methods:

    public String Foo.toJson() {
    public static Foo Foo.fromJsonToFoo(String json) {
    public static String Foo.toJsonArray(Collection<Foo> collection) {
    public static Collection<Foo> Foo.fromJsonArrayToFoos(String json) {

    Is there some other jackson jar I need?
    Or am I misunderstanding how this is supposed to work?

    Thanks

    -Bruce

  • #2
    I think you're misunderstanding in the same way I was.

    I presume that they mean you can use EITHERthe JSON addon (Option 1) OR Spring MVC in the usual way (to detect the Jackson library in the application classpath)

    I've just tried the Keith Donald's tutorial (http://blog.springsource.com/2010/01...in-spring-3-0/) but using Roo:

    Code:
    // Spring Roo 1.1.5.RELEASE [rev d3a68c3] 
    project --topLevelPackage com.malsolo.samples.mvc --projectName mvc-ajax-roo --java 6
    persistence setup --provider HIBERNATE --database POSTGRES --databaseName DATABASE --hostName localhost --userName USERNAME --password *********
    entity --class ~.ajax.account.domain.Account --testAutomatically
    field string --fieldName name --sizeMin 1 --sizeMax 25 --notNull
    field number --type java.math.BigDecimal --fieldName balance --notNull --value 1000
    field number --type java.math.BigDecimal --fieldName equityAllocation --notNull --value .60
    field date --type java.util.Date --fieldName renewalDate --future --dateTimeFormatPattern S-
    perform tests
    controller scaffold --entity ~.ajax.account.domain.Account --class ~.ajax.account.web.AccountController
    selenium test --controller ~.ajax.account.web.AccountController
    dependency add --groupId org.codehaus.jackson --artifactId jackson-jaxrs --version 1.8.5
    finder list --class ~.ajax.account.domain.Account
    finder add --finderName findAccountsByNameEquals
    dependency remove --artifactId flexjson --groupId net.sf.flexjson --version 2.1
    It worked.

    (NOTE: you need to add JQuery to the application in order to have the same code as Keith Donald. It isn't difficult, but it's a little bit long to write it down at this moment)
    Last edited by jbbarquero; Sep 15th, 2011, 06:24 AM. Reason: Privacy

    Comment


    • #3
      I'm missing something basic here as to me it looks like your sample roo script above creates a CRUD web UI using the roo scaffolded jsp views mechanism.
      I believe the:
      controller scaffold --entity ~.ajax.account.domain.Account --class ~.ajax.account.web.AccountController
      Create the web UI that one can use with a browser directly.

      I don't see any json exposed API here.

      From STS, selecting spring->show reource mappings, there are no rest methods exposed.

      Also it's using:
      Code:
      UrlBasedBiewResolver
      I thought that when using jackson one would leverage:
      Code:
      ContentNegotiatingViewResolver
      Quoting the docs again:
      Option 2: Spring MVC detects the Jackson library in the application classpath

      simply use Spring's @RequestBody and @ResponseBody annotations in the controllers, or

      take advantage of Spring's ContentNegotiatingViewResolver
      I also don't see any @RequestBody and @ResponseBody in the generated .aj files.

      Maybe I'm asking too much that roo "just do it" and I need to config a bunch of this stuff manually, but I thought that was the beauty of roo in that it did "just work".

      I don't see how one gets any REST API out of roo when using either the old:
      Code:
      controller scaffold
      or the new:
      Code:
      web mvc scaffold
      What am I missing?

      Does one need to chuck all the generated controller methods and recode using @RequestBody and @ResponseBody annotated methods? If that's the case, what does the mvc scaffolding but you if the end goal is jackson mapped json?

      -Clueless and getting deeper

      Comment


      • #4
        What you're missing is to manually change the code to follow the Option 2: to let Spring MVC deal with JSON with Jackson in the classpath.

        I meant I created the mvc-ajax project using Roo and I called it mvc-ajax-roo. Then, I modified it using the code that Keith Donald shared in his POST. Take a look to it. Because you're right, @RequestBody or @ResponseBody annotations in the controllers are needed.

        [By the way, congratulations to the Roo team project, because it's wonderful how an entire web project is created with just a few lines of scripting (actually I don't matter to write thousands of lines of code if necessary, but I hate to write XML files and deal with the issues that can arise)]

        For instance, here is the code that I copied from the Keith Donald's sample:

        Code:
        @RooWebScaffold(path = "accounts", formBackingObject = Account.class)
        @RequestMapping("/accounts")
        @Controller
        public class AccountController {
        	
        	@RequestMapping(value="/availability", method=RequestMethod.GET)
        	public @ResponseBody AvailabilityStatus getAvailability(@RequestParam String name) {
        		for (Account a : Account.findAccountsByNameEquals(name).getResultList()) {
        			if (a.getName().equals(name)) {
        				return AvailabilityStatus.notAvailable(name);
        			}
        		}
        		return AvailabilityStatus.available();
        	}
        }
        So, there is no "Roo magic" here (by the way, I'm used to using "controller sc" instead of "mvc" because I work with Roo since the very first version)

        Comment


        • #5
          Now a question arises for me:

          I tried to debug the code in order to see the actual call to the MappingJacksonHttpMessageConverter, however, I can only see how it writes the response:

          Code:
          2011-09-16 09:13:13,826 [tomcat-http--29] DEBUG org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter - Written [com.malsolo.samples.mvc.ajax.account.AvailabilityStatus@119510f] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter@110860e]
          I can't see who is dealing with the request. I've put breakpoints in the "T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException;" method of all the implementing classes of the HttpMessageConverter that I've found: AbstractHttpMessageConverter<T>, BufferedImageHttpMessageConverter, FormHttpMessageConverter and ResourceHttpMessageConverter.

          The debug only stops at MappingJacksonHttpMessageConverter(AbstractHttpMes sageConverter<T>).write(T, MediaType, HttpOutputMessage) line: 166:

          Code:
          Daemon Thread [tomcat-http--19] (Suspended (breakpoint at line 166 in AbstractHttpMessageConverter))	
          	MappingJacksonHttpMessageConverter(AbstractHttpMessageConverter<T>).write(T, MediaType, HttpOutputMessage) line: 166	
          	AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.writeWithMessageConverters(Object, HttpInputMessage, HttpOutputMessage) line: 975	
          	AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.handleResponseBody(Object, ServletWebRequest) line: 933	
          	AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.getModelAndView(Method, Class, Object, ExtendedModelMap, ServletWebRequest) line: 882	
          	AnnotationMethodHandlerAdapter.invokeHandlerMethod(HttpServletRequest, HttpServletResponse, Object) line: 428	
          	AnnotationMethodHandlerAdapter.handle(HttpServletRequest, HttpServletResponse, Object) line: 414	
          	DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse) line: 790	
          	DispatcherServlet.doService(HttpServletRequest, HttpServletResponse) line: 719	
          	DispatcherServlet(FrameworkServlet).processRequest(HttpServletRequest, HttpServletResponse) line: 644	
          	DispatcherServlet(FrameworkServlet).doGet(HttpServletRequest, HttpServletResponse) line: 549	
          	DispatcherServlet(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 621	
          	DispatcherServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 722	
          	ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 304	
          	ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
          	OpenEntityManagerInViewFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 113	
          	OpenEntityManagerInViewFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 76	
          	ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243	
          	ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
          	HiddenHttpMethodFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 77	
          	HiddenHttpMethodFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 76	
          	ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243	
          	ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
          	CharacterEncodingFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 88	
          	CharacterEncodingFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 76	
          	ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243	
          	ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
          	StandardWrapperValve.invoke(Request, Response) line: 240	
          	StandardContextValve.invoke(Request, Response) line: 164	
          	NonLoginAuthenticator(AuthenticatorBase).invoke(Request, Response) line: 462	
          	StandardHostValve.invoke(Request, Response) line: 164	
          	ErrorReportValve.invoke(Request, Response) line: 100	
          	AccessLogValve.invoke(Request, Response) line: 562	
          	StandardEngineValve.invoke(Request, Response) line: 118	
          	HttpRequestOperationCollectionValve.invoke(Request, Response) line: 84	
          	CoyoteAdapter.service(Request, Response) line: 395	
          	Http11Processor.process(SocketWrapper<Socket>) line: 250	
          	Http11Protocol$Http11ConnectionHandler.process(SocketWrapper<Socket>, SocketStatus) line: 188	
          	JIoEndpoint$SocketProcessor.run() line: 302	
          	ThreadPoolExecutor$Worker.runTask(Runnable) line: 886	
          	ThreadPoolExecutor$Worker.run() line: 908	
          	TaskThread(Thread).run() line: 662
          I'm using Spring Roo 1.1.5, so the project uses Spring 3.0.5.

          By debugging in Chrome I can see:

          Headers:
          Code:
          Request URL:http://localhost:8080/mvc-ajax-roo/accounts/availability?name=Prueba
          Request Method:GET
          Status Code:200 OK
          Request Headersview source
          Accept:application/json, text/javascript, */*; q=0.01
          Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
          Accept-Encoding:gzip,deflate,sdch
          Accept-Language:en-US,en;q=0.8
          Connection:keep-alive
          Cookie:JSESSIONID=2ED8B19FF65518E3A643058BA6688BD5
          Host:localhost:8080
          Referer:http://localhost:8080/mvc-ajax-roo/accounts?form
          User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1
          X-Requested-With:XMLHttpRequest
          Query String Parametersview URL encoded
          name:Prueba
          Response Headersview source
          Content-Type:application/json;charset=UTF-8
          Date:Fri, 16 Sep 2011 06:52:53 GMT
          Server:Apache-Coyote/1.1
          Transfer-Encoding:chunked
          Content:
          Code:
          {"available":false,"suggestions":["Prueba1","Prueba2","Prueba3"]}
          JSON:
          Code:
          available: false
          suggestions: [Prueba1, Prueba2, Prueba3]
          0: "Prueba1"
          1: "Prueba2"
          2: "Prueba3"
          Can you explain me a little bit how the request is processed? I though I knew, but it doesn't seem true.

          Thanks.

          Comment


          • #6
            Originally posted by jbbarquero View Post
            What you're missing is to manually change the code to follow the Option 2: to let Spring MVC deal with JSON with Jackson in the classpath.

            I meant I created the mvc-ajax project using Roo and I called it mvc-ajax-roo. Then, I modified it using the code that Keith Donald shared in his POST. Take a look to it. Because you're right, @RequestBody or @ResponseBody annotations in the controllers are needed.

            [By the way, congratulations to the Roo team project, because it's wonderful how an entire web project is created with just a few lines of scripting (actually I don't matter to write thousands of lines of code if necessary, but I hate to write XML files and deal with the issues that can arise)]
            I guess that was my conceptual stumbling block. It didn't seem reasonable to me that the roo docs would call out a method where the entire controller needed to be pushed-in and mechanically edited to change every single method - exactly the thing that roo relieves developers from doing. I had expected that there was some roo incantation that would do the bulk editing this requires. I have a very large service with many dozens of exposed entities and such a manual process is prohibitive. Aside from the large time block for the manual edits, it means that all the controller methods are now pushed-in and future roo generated entity changes are now all manual. It sort declares the end of roo's usefulness for large bulk architecture changes is one has to do this.

            This enhancement speaks to similar concerns albeit for slightly different reasons:
            https://jira.springsource.org/browse/ROO-1373
            I've added my $.02 for additional rationale as to why it's needed.

            jbbarquero - thanks for clearing up my misconception.

            Comment


            • #7
              I totally agree with you,

              I like Roo a lot, and I'm giving a chance to being improved, since it's only in its first version (1.2 not yet released)

              I specially like not having to configure the application (XMLs and so on) However, it's true that is very difficult to manage large systems, several data tables and customize the view in order to have a professional web site.

              I had already voted the JIRA ticket, but I've just added a couple of comments.

              Last but not least, I apology for bothering you with a simple example when both of us have to deal with very big Java EE concerns.

              Comment


              • #8
                No problem, sorry I couldn't help. I'm still getting my head around the whole MappingConverters etc.

                Take a look at this:
                http://www.rimple.com/process/Create...ntryId=8149020

                I followed those docs and got jsp AND rest direct from roo with no manual edits other than the webmvc-config.xml.

                Comment


                • #9
                  Hi guys,

                  Out of the box Roo currently uses FlexJson for JSON integration. Just dropping Jackson into the classpath will not disable the FlexJson integration. Jackson was initially not chosen because it had no automatic detection of cyclic references (something you see quite commonly in OO domains). I am not sure if that has changed in the meantime.

                  If you want to use Jackson, simply don't use Roo's default Json integration and add the config manually or try out one of the external add-ons that do it for you. 'addon search json' offers an add-on that has this functionality, although I have not tried it.

                  Comment


                  • #10
                    Hello Stefan,

                    Thanks for the answer.

                    I tried what you said and it worked.

                    The problem here is that we miss a json_jackson add-on in order to avoid as much manual editing as possible.

                    A mvc json_jackson is also desirable (and a jquery addon too, but it's out of the bounds of this POST)

                    Comment


                    • #11
                      Originally posted by Stefan Schmid[URL="http://wiki.fasterxml.com/JacksonAnnotations?highlight=%28cyclic%29%7C%28ref erences%29"
                      t;380325]Hi guys,

                      Out of the box Roo currently uses FlexJson for JSON integration. Ju[/URL]st dropping Jackson into the classpath will not disable the FlexJson integration. Jackson was initially not chosen because it had no automatic detection of cyclic references (something you see quite commonly in OO domains). I am not sure if that has changed in the meantime.

                      If you want to use Jackson, simply don't use Roo's default Json integration and add the config manually or try out one of the external add-ons that do it for you. 'addon search json' offers an add-on that has this functionality, although I have not tried it.
                      Stefan, thanks for the pointer. It appears the json addon is not available in 1.2.0.M1. Do addons need to be forward ported to each new roo version or is it a config issue?

                      Regarding jackson and cyclic refs, jackson claims to handle these since version 1.6:
                      http://wiki.fasterxml.com/JacksonAnn...8references%29

                      Comment


                      • #12
                        Hi Bruce, some add-ons which are Roo 1.1 compliant may work in 1.2 depending on which Roo APIs they use, some may not. We made a number of API changes between 1.1 and 1.2 so if there is an issue please raise a ticket here so the owner can look into it http://code.google.com/p/spring-roo-addons/issues/list.

                        As for the cyclic reference management in Jackson it appears this can now be managed through new annotations. However, that implies that Roo must scan your entire project for possible cycles and apply the annotations in some smart way to prevent cycles. This is currently not supported by Roo. Also, in many cases the developer (you) would know your domain better than Roo can understand it to make smart decisions about placing the annotations. With FlexJason cycle detection is built-in and it simply stops and ships the JSON document without cycles.

                        Comment

                        Working...
                        X