JSP recompilation needed? - java

I just want the general idea about what will happen in the following situation, without getting into the technical details.
The main advantage of JSP is that we have separate presentation (static HTML) and dynamic application logic. So we can make changes into either of them without affecting the other. Now suppose, we have a precompiled JSP into either a servlet or bytecode, and we want to make a change in the presentation part, would we then have to recompile the whole stuff, even though we did not make any change in the application logic?
Thanks everyone for the answer, but all the answers that I get do point to the fact that whether automatically or manually, the JSP does need to be recompiled into the servlet, which is then converted into the corresponding byctecode. In short a completely new file would be created I suppose.

As long as it is JSP, you dont need to compile/convert. The application server automatically translates your JSP into corresponding servlet, a Java file (on the first hit to the JSP), and then compiles it to class file. Whenever you update the JSP file and when the server receives request for that resource (JSP) it checks the last updated time and does the above job if required.

Yes and no. JSP's are ultimately compiled into servlets, but the servlet container will usually recompile the JSP for you if it has changed, which is a fairly quick operation.

No. If you change the JSP, generally speaking the servlet/jsp container will 'see' the jsp changed and will recompile it.
That being said, i'm not clear on your deployment model. if you're 'precompiling' the asps and adding those to your .war then you might be out of luck.

Related

Interact with JSP compiler

I have some text templates stored in a database. We need to use a templating engine to process these texts. We first thought of Velocity / Freemaker / Thymeleaf to process these texts. However, I thought (but could be wrong) that one could interact with the application server JSP compiler. I'd prefer to use JSP compiler rather than importing a new bunch of jars.
Thanks
AFAIK they are different concepts and work differently so they won't directly interact :
JSP is processed by a JSP compiler to generate java code for a servlet that is compiled (at run-time) in a .class file. It is later used by the servlet container as any other servlet. You can include any java code in a JSP with scriptlets (even if it now considered as bad practice)
template engines (Velocity / Freemaker / Thymeleaf) take a template and only allow to replace variable place holders with values at run time to produce text. Of course, they also allow tests and loops, but no java source nor class object is ever generated. In a web application they use one single servlet that takes the template and the replacement values and generate the text that will be sent in the response.
But of course as JSP can contain arbitrary java code, you could call a template engine from a JSP, but I really cannot imagine a proper use case.
Edit per comment:
You could try to use JSP as a template engine, but my advice is : don't do that ! You would need :
create a stub implementing ServletResponse where the getOutputStream() and the getWriter() methods end in a String.
force the ServletContainer to generate the java source and the class file - or manage to do that at compile time (I don't know how exactly how to do that, but I'm pretty sure it can be done)
at run time include the generated servlet with the response stub to generate the output String.
But beware, even if you succeed, it will lead to hardly maintainable code heavily coupled to a servlet container or using special steps (JSP -> java) at build time. As already said : don't do that.
I've just come to JSP compilation to string or in memory bytearray with Tomcat/Websphere, looks like your question is a duplicate of that one ...

Update classes and ressources of a Java Servlet when using Glassfish

In IDEA IntelliJ I have the option to:
Update resources
Update classes and resources
Redeploy
Restart server
If I change some code of a Servlet then I always need to redeploy. Is there another way to "reload" faster to get changes affected?
Check out this IntelliJ WebHelp article: Reloading Classes
However there are limitations:
At the moment due to original limitations of Java SDK the HotSwapping
is possible ONLY if a method body is altered. In all other cases (like
changing method or class signature), the class reload is impossible
and the corresponding error message appears.
For more options you might want to check out what Engineer Dolly suggested in his comment to your question.

Read a JSP file and produce HTML - not with a web server

If I wanted to read a jsp like:
File f = new File("my.jsp");
and then I want it to produce the expected HTML as say a String (byte[], OutputStream, whatever), How would I do that?
I assume there is some transformer or something. Can anyone point me in the right direction?
A JSP File is translated and compiled as a Servlet class, so it not directly generate a html File, the reason is a JSP as a Servlet could generate dynamic html depending of the parameters in the request, in the tomcat server it use the Jasper 2 JSP Engine to implement the JavaServer Pages 2.1 specification that process the JSP, so you can check it but I don't recommend you do that.
Maybe what your really want is a template mechanism, for example you have a text file similar to the jsp with similar sintax to the EL that can access some objects, so you can use the template engine and bound your object with the text and produce your html. If it works for you, you can use Apache Velocity - HTML example or FreeMaker - HTML example.
Jasper is the JSP compiler used by Tomcat, it takes the JSP pages themselves, parses them, and generates Java code (in the form of a servlet, or at least it used to be) which writes the JSP's output to the servlet response. That Java code would then be compiled and executed against the containers implementation of the Servlet API.
Jasper is a standalone library, so in theory you could instantiate its classes inside your own harness, point it at a JSP, generate the servlet code, then compile and execute it. However you'd need to pass in your own mock implementations of the Servlet API interfaces, as it's these that will be called to determine request parameters (HttpServletRequest), and to write the response (HttpServletResponse). You'd need to provide a version of HttpServletResponse that will buffer up the output for you to grab later.
From the Tomcat 6 API, this bits your want are in the org.apache.jasper package.
Taking a look at at it you'd probably want to create a JspCompilationContext which points to your JSP, call createCompiler(), and take it from there.
As far as mocking out the Servlet API goes, you might get what you need from the stub implemetations provided by the Spring Framework for testing purposes
Velocity and FreeMarker are both excellent for this, and much easier for basic templating.
However, it can be done.
I have an example explained here: Tomcat JSP/JSTL without HTTP
It's obviously easier from within a web app (as all of the jars will be there), but it can be done outside, you'll just need to identify and the appropriate jars to your program.

Execute JSP directly from Java

I need to execute a JSP. But I need to directly from Java, without using Tomcat or any other servlet container. Compiling JSPs would be a good thing too, but not necessary. I think maybe org.apache.jasper package is good for doing this, but I can't find any good example or tutorial online.
I need something as:
Class compiledJSP = compileJSP(new File("helloWorld.jsp"));
String html = executeJSP(compiledJSP, httpServletRequest, httpServletResponse, ...);
html --> "Hello World, John!"
Thanks!
If you need to capture JSP's output as string it's reasonably straightforward (although far from ideal from the design point of view) from within Servlet Container:
1. Extend javax.servlet.HttpServletResponseWrapper and override getWriter() / getOutputStream() methods to provide your own buffered versions (e.g. StringWriter)
2. Invoke "include()" method of RequestDisparcher, wrapping original response in your own.
3. Grab buffer's content.
Now if you need to do the same thing outside Servlet Container, you really need to ask yourself "why?". Perhaps you should be using a template engine (FreeMarker / Velocity / StringTemplate / etc...) instead of JSPs? If your JSPs are well-formed XML files and are not using any java code inserts it may be reasonably trivial to convert them to FreeMarker templates (FreeMarker supports custom JSP tag libraries) which would greatly simplify your task.
Nevertheless, if it's an absolute hard requirement your most straightforward options are:
1. Run an external Servlet Container and let it handle JSP interpretation. Your program would submit HTTP requests to it and capture the output.
2. Same as above, but you can run embedded Servlet Container (e.g. Jetty).
If your JSPs are available at build-time you can precompile them via Jasper as suggested in other answers.
I would strongly advice against trying to implement your own servlet container - you'll be walking into a world of hurt.
You will need a container. A JSP is an abstraction on Servlet. Servlets have a dependency on a life cycle provided by a container.You need a container to provide the life cycle.
This is possible without a servlet container. There are two steps to it.
The first is to generate the source code. If you look at the source code of the jspc ant task it is possible to do it directly in code. Or you could just invoke the ant task.
The code that is generated is just a Servlet and it is possible to invoke the methods on a servlet outside of a container:
Just instantiate it and then call doGet(request, response). I'm not sure exactly what you need this for but your life will be made easier using spring mock objects for the http request and response.
This will populate the Response object. you can then get the output with:
res.getContentAsString();
See an example here:
http://ytreyvus.blogspot.com/2007/03/private-void-cloneplaneffectrelationshi.html
Try MockRunner to execute it. You'll need to compile the JSP first, though. I'm using Maven 2 for this (and the JSP Compiler plugin)

How can you force recompilation of jsps in JBoss 4.2?

I hit on this nasty behavior on JBoss 4.2 in QA, and I want to nip it in the bud before we go into production and find some other corner case.
A jsp calles a method that had the following signature:
public void methodName(String arg)
This was changed to:
public void methodName(String arg, Object... args)
A pre-existing JSP called this method via:
methodName("param");
On deployment of the modified code, JBoss did not recompile the JSP and this caused a crash in QA. Adding a silly comment to the jsp fixed the problem (JBoss recognized that the JSP changed and recompiled it).
Is there a setting on JBoss to force recompilation of JSPs on restart?
EDIT: To clarify some points in the answer, the setup is that the JSPs are part of a war which is part of an ear. The ear has all classes in it, in a jar.
Regarding the desire to pre-compile, if the system doesn't think that the jsp needs compilation, will pre-compile force recompilation? It doesn't seem so. The error here is not a compliation error, it is a method invocation error because of the "changed" (at the byte code level, not really at the code level) method signature.
Addendum: Note that we experienced in production recently that even with the accepted answer's flag set the JSPs did not recompile, even though the JSP did in fact change. Major bug there, but regardless, JBoss was shutdown normally. At this point it is getting to be an old version of JBoss, but if you are still using it, deleting the content of the work and tmp directories is the only way to be sure.
I'm not changing the accepted answer simply because it really gets to the point of what the question was looking for. JBoss bugs are kind of a separate issue.
If the JSPs are part of a WAR that is part of an EAR that is being deployed as a jar, then I'm not clear why your JSPs are not being recompiled. Don't the JSPs in the war file have newer timestamps than their JBoss-compiled class files from the last deploy? If not, couldn't you touch the JSPs as part of building the WAR/EAR before deploying. [I'm referring to using the Unix "touch" command, not manually touching each JSP file.]
Alternatively, the DeleteWorkDirOnContextDestroy setting in $JBOSS/server/default/deploy/jboss-web.deployer/META-INF/jboss-service.xml may be what you are looking for. It is false by default, but setting it to true may be what you need. I think this should delete the JSPs' class files on redeploy so that they get recreated upon first access of each JSP.
See https://jira.jboss.org/jira/browse/JBAS-3358 for more info.
I don't know of a setting, but deleting the generated Java class file in the work directory of your JBoss instance will cause the JSP to be recompiled the next time it is called.
You coudl alter the JBoss startup scripts to explicitly delete the "tmp" and/or "work" directories, where the compiled JSPs are stored. JBoss would then have no choice but to recompile them all.
Not subtle, but it would do the job.
One option for you would be to precompile all of your jsp's at build time. This would quickly flag any compilation errors.
You could also do this in production - speeding up first access but I get the feeling you want this more for a QA step than anything else. If so, you could add the precompile step to the your testing phase in your build tool of choice - and so to your CI environment. This would provide assurance that jsp's that don't compile won't make it out of test.
See this for details on running a precompile task:
Jboss Jasper configuration
Hope this helps.
Some JSP containers (as per section 8.4.2 of the JSP 1.2 specification) support the capability of precompiling a JSP page.
To precompile a JSP page, access the page with a query string of ?jsp_precompile
http://hostname.com/mywebapp/mypage.jsp?jsp_precompile
The JSP page will not be executed. If the container supports precompilation, the JSP page will be compiled if necessary.
See also http://www.rgagnon.com/javadetails/java-0414.html
Pablojim is on the right track. You just need some more info to get a complete view of what's going on. Here's how I understand it.
In prod, you've changed a jsp that requires other jsps to be recompiled. In order for them to be recompiled one of 2 things must happen
The compiled version of the jsp needs to be deleted.
The jsp itself needs to be modified (or even if it's "touched" - modified date is updated)
If you still need to verify that all your jsps work, they will all need to be precompiled using an ant task. this also allows you to deploy the war file with the precompiled jsps in the war file. This should solve your problem.
If your files are not deployed in a war file, but in an exploded format, you should seriously consider packaging your web app in a war file for deployment. This makes it a nice package to deploy between environments.

Categories

Resources