{"id":18076603,"url":"https://github.com/ggeorgovassilis/fauxjsp","last_synced_at":"2025-04-12T08:26:11.101Z","repository":{"id":39635890,"uuid":"28683775","full_name":"ggeorgovassilis/fauxjsp","owner":"ggeorgovassilis","description":"JSP implementation with fast page reloads that uses an interpreter rather than a compiler ","archived":false,"fork":false,"pushed_at":"2022-12-10T11:45:43.000Z","size":1255,"stargazers_count":6,"open_issues_count":5,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-26T03:33:17.287Z","etag":null,"topics":["jsp","tagfiles","taglib"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ggeorgovassilis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-01-01T09:14:39.000Z","updated_at":"2023-12-23T00:17:22.000Z","dependencies_parsed_at":"2023-01-26T06:31:26.641Z","dependency_job_id":null,"html_url":"https://github.com/ggeorgovassilis/fauxjsp","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggeorgovassilis%2Ffauxjsp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggeorgovassilis%2Ffauxjsp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggeorgovassilis%2Ffauxjsp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggeorgovassilis%2Ffauxjsp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ggeorgovassilis","download_url":"https://codeload.github.com/ggeorgovassilis/fauxjsp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248538671,"owners_count":21121022,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jsp","tagfiles","taglib"],"created_at":"2024-10-31T11:10:35.455Z","updated_at":"2025-04-12T08:26:11.077Z","avatar_url":"https://github.com/ggeorgovassilis.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"https://travis-ci.org/ggeorgovassilis/fauxjsp.svg\"/\u003e \u003cimg src=\"https://coveralls.io/repos/github/ggeorgovassilis/fauxjsp/badge.svg?branch=master\"/\u003e [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.ggeorgovassilis/fauxjsp/badge.png)](https://maven-badges.herokuapp.com/maven-central/com.github.ggeorgovassilis/fauxjsp/)\n\nfauxjsp\n=======\n\nfauxjsp is a [Java Server Pages (JSP)](http://www.oracle.com/technetwork/java/index-jsp-138231.html) implementation for use during development: JSPs are interpreted lazily (instead of compiled) which reduces application and page startup times, speeds up page reloads when JSPs change and doesn't require server restarts. Best used when developing, can be used in production also if specification compliance isn't critical.\n\n## TL;DR\n\n```xml\nweb.xml:\n\u003cservlet\u003e\n        \u003cservlet-name\u003eFauxJsp\u003c/servlet-name\u003e\n        \u003cservlet-class\u003efauxjsp.servlet.JspServlet\u003c/servlet-class\u003e\n\u003c/servlet\u003e\n\n\u003cservlet-mapping\u003e\n\t\u003cservlet-name\u003eFauxJsp\u003c/servlet-name\u003e\n\t\u003curl-pattern\u003e*.jsp\u003c/url-pattern\u003e\n\u003c/servlet-mapping\u003e\n```\n\nVersions below (and including) 1.2.3 are in maven central:\n\n```xml\npom.xml:\n\u003cdependency\u003e\n\t\u003cgroupId\u003ecom.github.ggeorgovassilis\u003c/groupId\u003e\n\t\u003cartifactId\u003efauxjsp\u003c/artifactId\u003e\n\t\u003cversion\u003e1.2.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nVersions after 1.2.3 require a repository:\n\n```xml\n\u003crepositories\u003e\n\t\t\u003crepository\u003e\n\t\t\t\u003cid\u003efauxjsp-repo\u003c/id\u003e\n\t\t\t\u003curl\u003ehttps://github.com/ggeorgovassilis/fauxjsp/raw/gh-pages/\u003c/url\u003e\n\t\t\t\u003csnapshots\u003e\n\t\t\t\t\u003cenabled\u003etrue\u003c/enabled\u003e\n\t\t\t\t\u003cupdatePolicy\u003ealways\u003c/updatePolicy\u003e\n\t\t\t\u003c/snapshots\u003e\n\t\t\u003c/repository\u003e\n\u003c/repositories\u003e\n```\n\n\n## Change log\n\n\n1.2.7-SNAPSHOT (not released on maven central)\n- improved scriptlet execution performance\n\n1.2.3\n- less aggressive HTML escaping (don't escape high-end unicode characters)\n\n1.2.2\n- performance test extends to scriptlets, minor refactoring\n\n1.2.1\n- fixed bug in resolving classpath includes\n\n1.2.0\n- permanently caching parsed JSP and tagfiles in \"production\" mode\n\n1.1.0\n- simplified EL expression handling, improved rendering performance\n\n1.0.0\n- handling `trimDirectiveWhiteSpaces`, `c:set` body content implemented\n\n0.0.9\n- released to maven central, otherwise identical to 0.0.5-SNAPSHOT\n\n0.0.5-SNAPSHOT\n- implemented \u003c%@page %\u003e directive for content type and character encoding\n- ability to handle tagfiles and JSPs in classpath locations\n- updated dependencies servlet-api 4.0.1, tomcat 9.0.8\n- handling Unicode in response\n- fixed bug in foreach handling\n- fixed bug in xml namespace parsing\n- housekeeping\n\n0.0.4-SNAPSHOT \n- Implemented JSP comments\n- populating context and session attributes as JSP variables\n- added sessionScope, contextScope, requestScope implicit objects\n- added empty applicationScope implicit object\n- able to iterate over arrays\n\n## Another JSP implementation?\n\nYes. In short:\n- a. there aren't that many (I only know of two, [Oracle JSP](https://docs.oracle.com/cd/B10501_01/java.920/a96657/orajspov.htm) and [Jasper](https://tomcat.apache.org/tomcat-6.0-doc/jasper-howto.html))\n- b. faster page reload than other implementations because it interprets JSP rather than compiling it to byte code\n- c. no memory leaks, more robust, more precise and helpful error messages for syntax- and runtime errors\n- d. extensible\n- e. if compliance and performance are not a top priority, it comes with a few neat features not available with standard JSP such as loading tagfiles and JSPs from the classpath.\n\nFor most of you cool dudes JSP is horribly out of fashion, but I like using it for prototyping and [tagfiles](http://docs.oracle.com/javaee/1.4/tutorial/doc/JSPTags5.html). Sadly and surprisingly, not many people know about tagfiles despite them being a well-supported and mature technique for creating reusable web UI components.\n\nStarting a JSP-heavy application is slow because other JSP implementations will first compile JSP and tagfiles to java source code, then to byte code and then to machine code. Also, when making changes to JSP files, the entire process has to be repeated which slows down development. At some point you'll even get unexplainable compile errors, class loading errors, run out of memory and the likes, you'll know you've had enough and you'll restart the servlet container.\n\nfauxjsp implements a JSP interpreter and a [JSP servlet](https://github.com/ggeorgovassilis/fauxjsp/blob/master/src/main/java/fauxjsp/servlet/JspServlet.java) which reads JSP files and interprets them on the fly, skipping compilation altogether. This brings the benefit of instant page reloads, fast application start times and robustness (no classloader fiddling!) but, obviously, the generated JSP pages are slower under load than the standard implementation which may be an issue in production.\n\nCurrently implemented features:\n\n* Renders JSP pages\n* Renders tagfiles\n* Supports most core JSTL taglibs\n* Supports scriptlets\n* Is modular and extensible\n* Supports an idiomatic way of loading tagfiles and JSPs from the classpath\n\nConstraints and missing features:\n\n* Out-of-the-box only core taglibs are supported. This means that core taglibs like ```c:out``` will work but\n  third party taglibs such as [displaytag](http://www.displaytag.org) won't, unless you re-implement them for fauxjsp.\n* Not all core taglibs are supported and not all features of the supported ones are implemented which is not an intentional omission. Please submit a bug report if you think something is missing.\n* I didn't read up on JSP/JSTL/servlet specifications, the implementation is empirical (aka \"works for me\").\n* Servlet containers needs to provide some EL 3.0 implementation (i.e. works with Tomcat 8, not with Tomcat 7)\n* I didn't read up on variable scoping; scopes work similarly to variable scopes in Java blocks.\n* Encoding is pinned to UTF-8.\n* Not all JSP [implicit objects](https://docs.oracle.com/cd/E19316-01/819-3669/bnaij/index.html) are available.\n* Newline handling in output may differ from standard JSP implementations.\n* Scriptlets are implemented via [beanshell](http://www.beanshell.org) which means that there might be deviations from how scriptlets are handled in Jasper et al.\n* The JSP language ecosystem is rather complex; HTML, JSTL, EL and scriptlets are frequently mixed in the same file which is hard to parse. fauxjsp uses a very simple parser which means that it's likely to get confused by characters in EL expressions which have special meaning in XML, e.g.\n\"\u003c\" or \"\u003e\" as strings in scriptlets, \"{\" or \"}\" as strings in EL - you might have to use [named entities](https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references). Note that release 0.0.4 significantly improved handling of such characters.\n* Does not support web fragments\n* Uses a ```classpath:``` prefix for resolving tagfiles and JSPs in the classpath. Does not support the standard way of resolving classpath resources.\n\n### With all these restrictions, why should you bother?\n\nBecause:\n\n* JSPs and tagfiles reload instantly saving you plenty of time and server restarts.\n* fauxjsp implements a subset of the JSP specification; if it works in fauxjsp, it will probably work in Jasper, too.\n* it's tested on large and complex pages and the important things seem to work\n\nBonus:\n\n* If you're willing to abandon the standard JSP implementation, then fauxjsp comes with a few neat extra features and simplifications not available in standard JSP\n\n## Getting started\n\n1) add the dependency to your project\n\n```xml\n\u003cdependency\u003e\n\t\u003cgroupId\u003ecom.github.ggeorgovassilis\u003c/groupId\u003e\n\t\u003cartifactId\u003efauxjsp\u003c/artifactId\u003e\n\t\u003cversion\u003e1.1.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n*OR*\n\ndownload sources and compile\n\n```sh\ngit clone https://github.com/ggeorgovassilis/fauxjsp.git\ncd fauxjsp\nmvn install\n```\n\n3) Declare an instance of the JspServlet in web.xml:\n\n```xml\n\u003cservlet\u003e\n        \u003cservlet-name\u003eFauxJsp\u003c/servlet-name\u003e\n        \u003cservlet-class\u003efauxjsp.servlet.JspServlet\u003c/servlet-class\u003e\n\u003c!-- optionally specify a root for resource lookup, defaults to \"/\"\n\t\t\u003cinit-param\u003e\n\t\t\t\u003cparam-name\u003ebase-path\u003c/param-name\u003e\n\t\t\t\u003cparam-value\u003e/WEB-INF/jsp/\u003c/param-value\u003e\n\t\t\u003c/init-param\u003e\n--\u003e\n\u003c/servlet\u003e\n\n\u003cservlet-mapping\u003e\n\t\u003cservlet-name\u003eFauxJsp\u003c/servlet-name\u003e\n\t\u003curl-pattern\u003e*.jsp\u003c/url-pattern\u003e\n\u003c/servlet-mapping\u003e\n```\n\n## Run-time Dependencies\n\n* JSP API 2.0\n* Java EL 3.0 API\n* JSTL 1.2\n* Servlet API 4.0\n* commons-lang 2.6\n* beanshell 2.0b5\n* log4j 4\n\nServlet API, JSTL, EL are scoped as ```provided``` because the servlet container or the web application contribute these dependencies\n\nlog4j, Beanshell are scoped as ```provided``` because they are optional\n\ncommons-lang is scoped as ```compile``` because it's mandatory\n\nFor up-to-date details, [please see the pom](pom.xml).\n\n## Extending fauxjsp's functionality and working around bugs\n\nPlease submit a bug report when you find a bug or require a feature implemented. Now, in real (project) life, \nyou are probably on a tight schedule and don't want to wait for an official fix. fauxjsp is modular and easily\nextensible. So have a look at the next chapter about fauxjsp's architecture which will help you understand the various,\nrather simple components, how to modify them and implement new functionality.\n\n## Architecture overview\n\n### JspServlet\n\n```JspServlet``` accepts an HTTP request and renders the requested JSP. The entire sequence looks like this:\n\n1. Gets the requested JSP file's name from the ```ServletRequest```\n2. Looks at ```jspbase``` (see javadocs for ```JspServlet```) for the JSP file\n3. Asks the ```JspParserFactory``` for a new ```JspParser```\n4. Gives the JSP file to the ```JspParser``` who parses it, recursively resolves dependencies and returns a ```JspPage```\n5. Creates a new ```RenderSession```\n6. Asks the ```JspRendererFactory``` for a new ```JspRenderer```\n7. Gives the ```JspPage``` and ```RenderSession``` to the ```JspRenderer``` who renders it\n8. Streams the results to the browser\n\n```JspServlet``` has a bunch of protected methods which construct the various factories mentioned earlier. Should you need special setups\nthen overriding these constructor methods allows you to specify your own factories which can return modified or completely new implementations\nof parsers and renderers.\n\n### JspParser\n\nThe ```JspParser``` and more specifically its only implementation ```JspParserImpl``` is given a JSP file location, renders it and returns\nthe parsed results. In detail:\n\n1. ```JspParser.parse(path)``` is given the path of the JSP file to render\n2. The parser gives the path to a ```ResourceResolver``` instance (the ```JspParserFactory``` sets that one up) which returns\n   the JSP file as a string.\n3. The parser reads through the JSP file creating a tree of ```JspNode```s.\n4. When the parser finds taglib (or tagfile) declarations, it puts them into the ```TagLibDefinitionCache``` which makes sure that\n   taglibs are read only once during each request.\n5. When the parser meets tagfile declarations, it asks the ```JspParserFactory``` for a new parser who recursively parses the tagfile.\n\nUnfortunately, currently it is not possible to load taglibs other than tagfiles. However it is possible to use missing taglibs by providing a special implementation for fauxjsp yourself. Depending on the taglib you are trying to simulate this may or may not be\na labour-intensive task. For some examples, have a look at the ```JstlCoreTaglib*``` classes. The ```DefaultJspParserFactoryImpl``` factory sets those\nup under a special namespace, one for each taglib method.\n\n## Supported taglibs\n\n### Directives\n\n```xml\n\u003c%@ taglib prefix uri tagdir%\u003e\n\n\u003c@ include file %\u003e\n\n\u003c%@ attribute name required rtexprvalue type %\u003e\n\n\u003cjsp:attribute name=\"...\"\u003e...\u003c/jsp:attribute\u003e\n\n\u003cjsp:body\u003e...\u003c/jsp:body\u003e\n\n\u003cjsp:doBody/\u003e\n```\n\n### Core taglib\n\n```xml\n\u003cc:out value=\"...\"/\u003e\n\n\u003cc:choose test=\"...\"\u003e...\u003c/c:choose\u003e\n\n\u003cc:when test=\"...\"\u003e...\u003c/c:when\u003e\n\n\u003cc:otherwise\u003e...\u003c/c:otherwise\u003e\n\n\u003cc:forEach var=\"...\" items=\"...\" varStatus=\"...\" begin=\"...\" end=\"...\"\u003e...\u003c/c:forEach\u003e\n\n\u003cc:if test=\"...\"\u003e...\u003c/c:if\u003e\n\n\u003cc:set var=\"...\" value=\"...\"/\u003e\n\n```\n\n### Formatting and internationalisation\n\n```xml\n\u003cfmt:message key=\"...\"/\u003e\n\n\u003cfmt:setBundle basename=\"...\"/\u003e\n\n\u003cfmt:formatNumber value=\"...\" .../\u003e\n\n\u003cfmt:formatDate value=\"...\" .../\u003e\n\n\u003cfmt:setLocale value=\"...\"/\u003e\n\n```\n\n### Functions\n\nfauxjsp delegates to the standard JSTL function implementation used by the application server, so everything should work out of the box.\n\nIf you need more function taglibs, don't forget to declare them in web.xml:\n```xml\n\u003cjsp-config\u003e \n\t\u003ctaglib\u003e\n\t\t\u003ctaglib-uri\u003ehttp://java.sun.com/jstl/core-rt\u003c/taglib-uri\u003e\n\t\t\u003ctaglib-location\u003eMETA-INF/c-1_0-rt.tld\u003c/taglib-location\u003e\n\t\u003c/taglib\u003e\n\u003c/jsp-config\u003e\n```\ntaglib-location can be a server- or classpath resource path. \n\n## How do I ...\n\n### ... add a missing tag library?\n\nAs written before, fauxjsp can't use taglibs and has to emulate them instead, which means that someone has to program that emulation.\n\n*Step 1*: create the taglib implementation. Just find one of the already simulated taglibs like [JstlCoreTaglibOut](src/main/java/fauxjsp/impl/simulatedtaglibs/core/JstlCoreTaglibOut.java) and copy \u0026 paste it\n\n```java\n\npublic class TaglibAdd extends TaglibDefinition{\n\n\tprotected void runAdd(RenderSession session, JspTaglibInvocation invocation) {\n\t\tString xExpression = invocation.getArguments().get(\"x\");\n\t\tif (xExpression == null)\n\t\t\tthrow new RuntimeException(\"Missing x argument\");\n\t\tObject x = session.elEvaluation.evaluate(xExpression, session);\n\n\t\tString yExpression = invocation.getArguments().get(\"y\");\n\t\tif (yExpression == null)\n\t\t\tthrow new RuntimeException(\"Missing y argument\");\n\t\tObject y = session.elEvaluation.evaluate(yExpression, session);\n\t\t\n\t\ttry {\n\t\t    int ix = (Number)x;\n\t\t    int iy = (Number)y;\n\t\t    String s = \"\"+(ix+iy);\n\t\t\tsession.response.getOutputStream().write((s).getBytes(session.response.getCharacterEncoding()));\n\t\t} catch (Exception e) {\n\t\t\tthrow new JspRenderException(invocation, e);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void render(RenderSession session, JspTaglibInvocation invocation) {\n\t\trunAdd(session, invocation);\n\t}\n\t\n\tpublic TaglibAdd() {\n\t\tthis.name=\"add\";\n\t\tthis.attributes.put(\"x\", new AttributeDefinition(\"x\", Integer.class.getName(), true, true));\n\t\tthis.attributes.put(\"y\", new AttributeDefinition(\"y\", Integer.class.getName(), true, true));\n\t}\n}\n\n\n```\n\n*Step 2*: extend [DefaultJspParserFactoryImpl](src/main/java/fauxjsp/impl/parser/DefaultJspParserFactoryImpl.java) and override the ```setup``` method. Here you can register the new taglib you wrote\n\n```java\n\tpublic class MyJspParserFactory extends DefaultJspParserFactoryImpl{\n\t\t\n\tprotected void setup(JspParserImpl parser) {\n\t  super.setup(parser);\n\t\tparser.registerTaglibDefinition(\n\t\t\t\t\"http://mytaglibs/add\",\n\t\t\t\tnew TaglibAdd());\n\t}\t\t\n\t}\n\n```\n\n*Step 3*: extend [JspServlet](src/main/java/fauxjsp/servlet/JspServlet.java) and override ```getJspParserFactory``` so that it returns your new factory\n\n```java\n\tpublic class MyJspServlet extends JspServlet{\n\n\tprotected JspParserFactory getJspParserFactory(ServletConfig config){\n\t\tResourceResolver location = new ServletResourceResolver(jspBase, getServletContext());\n\t\tDefaultJspParserFactoryImpl factory = new MyJspParserFactory(location);\n\t\treturn factory;\n\t}\n\t\t\n\t}\n\n```\n\n\n*Step 4*: use your new JspServlet implementation in web.xml instead of the old JspServlet \n\n```xml\n\u003cservlet\u003e\n        \u003cservlet-name\u003eFauxJsp\u003c/servlet-name\u003e\n        \u003cservlet-class\u003eMyJspServlet\u003c/servlet-class\u003e\n\u003c/servlet\u003e\n\n\u003cservlet-mapping\u003e\n\t\u003cservlet-name\u003eFauxJsp\u003c/servlet-name\u003e\n\t\u003curl-pattern\u003e*.jsp\u003c/url-pattern\u003e\n\u003c/servlet-mapping\u003e\n```\n\n### ... enable logging to see what's going on?\n\n```JspServlet``` logs through log4j, if found on the classpath, otherwise through the standard JDK logging mechanism.\nA possible logging setup in ```log4j.properties``` could look like this:\n\n```\nlog4j.rootLogger=INFO, stdout\nlog4j.logger.fauxjsp=INFO, stdout\nlog4j.additivity.fauxjsp.impl.parser.JspParserImpl=false\n\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n\n```\n\n### ... work with scriptlets?\n[Scriptlets](https://docs.oracle.com/javaee/5/tutorial/doc/bnaou.html) are implemented with the use of [beanshell](http://www.beanshell.org), thus some deviations from the standard scriptlet behavior are to be expected. Scriptlets won't be enabled\nunless the Beanshell interpreter is found on the classpath. Current limitations are:\n\n* Not all [implicit objects](https://docs.oracle.com/cd/E19316-01/819-3669/bnaij/index.html) are available.\n* Beanshell's syntax is lenient; you can do things in Beanshell that you can't do in Java.\n* Beanshell doesn't understand vararg method signatures, e.g. you can't use [String.format](http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#format%28java.util.Locale,%20java.lang.String,%20java.lang.Object...%29) unless you pack arguments into an Object array. For more see [String formatting with beanshell](http://jedit.9.x6.nabble.com/String-formatting-with-beanshell-td1775061.html).\n\n### ... deal with a fauxjsp limitation?\nIdeally you'd find a way that works both in the production JSP environment as well as with fauxjsp. An example would be the case of\nvarargs used in scriptlets we talked about earlier. The fauxjsp parser is likely to be confused by strings that appear in EL expressions and scriptlets which are used elsewhere as delimiters like \u003c, \u003e, {, } etc. In that case try to use escapes like \\u007B for {.\n\n### ... reference tagfiles or JSPs which reside in the classpath?\nThe use case is that your tagfiles or JSPs reference other tagfiles or JSPs which reside in the classpath (eg. a JAR file).\nDon't use ```tagdir``` but use ```uri``` instead when including the resource, eg:\n````jsp\n\u003c%@ taglib prefix=\"cp\" uri=\"classpath:/tagfiles\" %\u003e\n````\n\n### ... make this work with Spring?\nYou probably noticed that the ```JstlView``` and ```InternalViewResolver``` don't work and Spring doesn't find your JSPs.\nUnder the hood, Spring should populate the model (the M in MVC) into the ```HttpServletRequest``` attributes and forward\nthe request to fauxjsp, but it doesn't. We can implement a simple forwarding mechanism like so:\n\n```java\nimport java.util.Locale;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.servlet.View;\nimport org.springframework.web.servlet.ViewResolver;\n\n@Component\npublic class ForwardingViewResolver implements ViewResolver{\n\n\t@Override\n\tpublic View resolveViewName(String viewName, Locale locale) throws Exception {\n\t\tForwardingView view = new ForwardingView();\n\t\tview.setUrl(\"classpath:/jsp/\"+viewName+\".jsp\");\n\t\treturn view;\n\t}\n}\n```\n\n```java\nimport java.util.Map;\nimport javax.servlet.RequestDispatcher;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletRequestWrapper;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.springframework.web.servlet.view.InternalResourceView;\n\npublic class ForwardingView extends InternalResourceView {\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic void render(Map\u003cString, ?\u003e model, HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows Exception {\n\t\tHttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(request) {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic String getServletPath() {\n\t\t\t\treturn getUrl();\n\t\t\t}\n\t\t};\n\t\texposeModelAsRequestAttributes((Map\u003cString, Object\u003e)model, wrapper);\n\t\texposeHelpers(wrapper);\n\t\tRequestDispatcher rd = request.getServletContext().getNamedDispatcher(\"FauxJsp\");\n\t\trd.forward(wrapper, response);\n\t}\n\n}\n```\n\nThe simple presence of those two components in the web application context should be enough for them to be picked up\nand activated.\n\n# ... enable caching?\n\n`JspServlet` can be configured to cache parsed JSPs. This is a minor performance improvement as normally rendering is\nslower than parsing.\n\n```xml\n\u003cservlet\u003e\n        \u003cservlet-name\u003eFauxJsp\u003c/servlet-name\u003e\n        \u003cservlet-class\u003efauxjsp.servlet.JspServlet\u003c/servlet-class\u003e\n\t\t\u003cinit-param\u003e\n\t\t\t\u003cparam-name\u003ecachePages\u003c/param-name\u003e\n\t\t\t\u003cparam-value\u003etrue\u003c/param-value\u003e\n\t\t\u003c/init-param\u003e\n\u003c/servlet\u003e\n```\n\n### How to remove excessive blanks and line breaks?\n\nSpecify a servlet init parameter `trimDirectiveWhiteSpaces`\n\n\n```xml\n\u003cservlet\u003e\n        \u003cservlet-name\u003eFauxJsp\u003c/servlet-name\u003e\n        \u003cservlet-class\u003efauxjsp.servlet.JspServlet\u003c/servlet-class\u003e\n\t\t\u003cinit-param\u003e\n\t\t\t\u003cparam-name\u003etrimDirectiveWhiteSpaces\u003c/param-name\u003e\n\t\t\t\u003cparam-value\u003etrue\u003c/param-value\u003e\n\t\t\u003c/init-param\u003e\n\u003c/servlet\u003e\n```\n\n## Roadmap\n\nFeatures to come ~~in the near~~ sometime in the future:\n\n* import\n* spring mvc taglibs\n\nScience fiction (things I have a rough idea how to implement but need to work out yet and may never come):\n\n* wrapper for using any third-party taglib\n* jsp debugger\n* running in more environments\n\n## Credits\n\nRoss Studtman for [JSP Tutorials](https://github.com/RossStudtman/JSP_Tutorials) which inspired many great\nunit tests.\n\n## License\n\nfauxjsp is available under the [GPL](http://www.gnu.org/copyleft/gpl.html). Since fauxjsp is a development tool, you normally wouldn't deploy it with your\napplication binaries into production, so the \"non-commercial\" aspect of the GPL doesn't affect your application.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fggeorgovassilis%2Ffauxjsp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fggeorgovassilis%2Ffauxjsp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fggeorgovassilis%2Ffauxjsp/lists"}