Class Specified in Method signature of TLD function is not found - JasperException - spring-boot

I am migrating a project from legacy spring to springboot. Project uses Spring Webflow and plan to keep the configurations intact for webflow and port the project to springboot by updating the project structure and adding necessary boot libraries.
Currently stuck with a jasperexception from the embedded tomcat jasper libraries complaining that the class used in the method signature of TLD for a function is not found.
org.apache.jasper.JasperException: The class [javax.servlet.http.HttpServletRequest request] specified in the method signature in TLD for the function [mytld:getAppLink] cannot be found. [javax.servlet.http.HttpServletRequest request]
at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:55) ~[tomcat-embed-jasper-9.0.36.jar!/:9.0.36]
at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:294) ~[tomcat-embed-jasper-9.0.36.jar!/:9.0.36]
at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:81) ~[tomcat-embed-jasper-9.0.36.jar!/:9.0.36]
If I update the function in TLD to a no argument function, it works fine at that point. But moment I have a class to pass in the constructor this error is thrown.
JSP:
<%# include file="/WEB-INF/jsp/includes/includes.jspf" %>
<%# taglib prefix="mytld" uri="MyTldLibrary" %>
<div id="header" class="style-header">
<div id="headm">
</div>
</div>
Here is snippet of my tld:
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_2.xsd"
version="2.0">
<tlib-version>2.2</tlib-version>
<jsp-version>3.0</jsp-version>
<short-name>mytld</short-name>
<uri>MyTldLibrary</uri>
<description>App EL Functions</description>
<function>
<name>getAppLink</name>
<function-class>
com.app.web.tags.AppWebFunctions
</function-class>
<function-signature>
java.lang.String getAppLink(javax.servlet.http.HttpServletRequest request)
</function-signature>
</function>
</taglib>
Here is snippet of function getAppLink from AppWebFunctions class:
/**
* Gets the App link.
*
* #param request the request
* #return the App link
* #throws UnsupportedEncodingException the unsupported encoding exception
*/
public static final String getAppLink(final HttpServletRequest request) throws UnsupportedEncodingException {
//LOGIC to retrieve applink
return appLink;
}

If I update the function in TLD to a no argument function, it works fine at that point. But moment I have a class to pass in the constructor this error is thrown.
That's because <function-signature> does not include any parameter names, only the fully-qualified class name of the parameter's type can be specified.
So, just remove the request parameter name and the TLD should work then.
<function-signature>
java.lang.String getAppLink(javax.servlet.http.HttpServletRequest)
</function-signature>

Related

SpringMVC - Error using mvcUrl - Missing WebApplicationContext

I am new to Spring MVC. I have basic Rest Controller and JSP. I want to be able to access the URL in the request mapping annotations from the JSP. I noticed that mvcUrl in Spring MVC 4.1 allows you to do that. But I run into an error when I try this:
When I open localhost/test.jsp. I see this in the browser:
org.apache.jasper.JasperException: javax.el.ELException: Problems calling function 's:mvcUrl'
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:556)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:477)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:395)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:339)
.....
java.lang.IllegalArgumentException: Cannot lookup handler method mappings without WebApplicationContext
org.springframework.util.Assert.notNull(Assert.java:115)
org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder.getRequestMappingInfoHandlerMapping(MvcUriComponentsBuilder.java:521)
org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder.fromMappingName(MvcUriComponentsBuilder.java:330)
org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder.fromMappingName(MvcUriComponentsBuilder.java:313)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
....
Here is some sample code that I used
#RestController
#RequestMapping("/foo")
public class FooRestController {
#RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
return "hello";
}
}
JSP File - test.jsp
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib uri="http://www.springframework.org/tags" prefix="s" %>
Link to Hello
What could be setup wrong?
When I hit localhost/foo/hello I do get back a json string "hello". Doesn't that mean the dispatcher servlet is working fine and the WebApplicationContext is actually setup properly?
The problem here is: you only defined controller handler for /foo/hello, but not for /test.jsp . Try adding a new controller:
#Controller
#RequestMapping("/")
public class GeneralController {
...
#RequestMapping(value = "/test.jsp", method = RequestMethod.GET)
public String hello() {
return "test"; // put the view name here. You won't need ".jsp" because it would be automatically added by the view resolver in the configuration below
}
}
and make sure similar code exists in your configuration, so that the system know where to look for your view
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/[Your_JSP_FOLDER]"/>
<property name="suffix" value=".jsp"/>
</bean>
This not a problem with your configuration file as you are using
#RestController annotaion in your controller which is a convenience annotation that is itself annotated with #Controller and #ResponseBody . as you may know annotating your class with #ResponseBody will return you back the json response from the method of the coltroller which is the expected behavior in this case.
If you want to get the jsp file what you should have used is
1.use #Controller instead of #RestController
2.Assuming you have configured view resolver with prefix and suffix for jsp page and return test string from the method because your jsp file name says it's name is test .
Hope this answer your question.
I don't think this is a configuration issue we have also faced similar kind of issues the only solution was to use modelandview instead of returning the view as string in the controller

Issue with creating Custom Tag Libraries in CQ5.5

I am creating a custom tag library and want to use it in one of my components. I have created a bundle which includes tag hello class which is extending TagSupport class and i created tags.tld file under my resource folder
In my pom.xml, I have used resource tag to include my .tld file in the generated jar file.
Here is my java class and tld file
TAG CLASS:-
package com.cb;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
/**
* Simple tag example to show how content is added to the
* output stream when a tag is encountered in a JSP page.
*/
public class Hello extends TagSupport {
private String name=null;
/**
* Getter/Setter for the attribute name
as defined in the tld file
* for this tag*/
public void setName(String value){
name = value;
}
public String getName(){
return(name);
}
/**
* doStartTag is called by the JSP container
when the tag is encountered */
public int doStartTag() {
try {
JspWriter out = pageContext.getOut();
out.println("<table border=\"1\">");
if (name != null)
out.println("<tr><td> Welcome <b>" + name +
"</b> </td></tr>");
else
out.println("<tr><td> Hello World </td></tr></table>");
} catch (Exception ex) {
throw new Error("All is not well in the world.");
}
// Must return SKIP_BODY because we are not
//supporting a body for this
// tag.
return SKIP_BODY;
}
/**
* doEndTag is called by the
JSP container when the tag is closed */
public int doEndTag(){
return EVAL_PAGE;
}
}
I also successfully installed the bundle in my felix console without having any error. Then i written custom tag in my jsp as below
JSP:-
<%#include file="/libs/foundation/global.jsp"%>
<%# page import="com.testcb.TestCustomTag"%>
<%# taglib prefix="mytest" uri="http://cs.test.com/bundles/cq/1.8"%>
<mytest:hello name="sachin"></mytest:hello>
I am getting the like "org.apache.sling.api.scripting.ScriptEvaluationException: org.apache.sling.scripting.jsp.jasper.JasperException: /apps/test/components/content/test/test.jsp(4,0) Unable to load tag handler class "com.cb.Hello" for tag "mytest:hello".
The same code is working fine in my apache tomcat server without having any issue. I am getting the error when i incorporate it in CQ.
What am i doing here? Is there any config i need to do in OSGI console to make it available?
UPDATE:
There was some problem with package name. Now Sling can read my tag handler class after i renamed the package name.
The error "Unable to load tag handler class" also has gone.
Now i am getting error as "org.apache.sling.api.scripting.ScriptEvaluationException: javax.servlet.ServletException: javax.servlet.jsp.JspException: com.testcb.TestCustomTag cannot be cast to javax.servlet.jsp.tagext.Tag"
I have the following dependency in pom.xml
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
And Here is my tld
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0">
<description>My tag library123</description>
<tlib-version>1.0</tlib-version>
<short-name>TagLib-Test</short-name>
<uri>http://cs.test.com/bundles/cq/1.0</uri>
<jspversion>2.1</jspversion>
<tag>
<name>testcustomtag</name>
<tagclass>com.testcb.TestCustomTag</tagclass>
<bodycontent>empty</bodycontent>
<info>This is a simple hello tag</info>
<attribute>
<name>name</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
Is there any problem with jsp version?
Please guide me to resolve.
Thanks
The tags.tld file needs to be under the META-INF folder. If you don't have it already you can create one under your resources source folder.
Yes, It is working as expected after i removed tag in pom.xml. This was the cause issues. :)
Thanks !

Spring Configuration of Custom Apache Camel Data Format

I am using Apache Camel 2.9.2 and Spring 3.0.6.RELEASE. I am trying to use a custom DataFormat to marshal and unmarshal Camel messages. I want to configure my custom DataFormat into one of my routes using Spring.
Apache Camel's documentation states that in order to hook up my custom Data Format to a route in Spring I simply need to declare my custom DataFormat as a bean and reference it inside of my Spring route like so:
<marshal>
<custom ref="myCustomDataFormat"/>
</marshal>
http://camel.apache.org/custom-dataformat.html
So I have the following setup:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<bean id="myCustomDataFormat" class="com.test.CustomDataFormat"/>
<!-- Camel Context -->
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="file:C:/test?initialDelay=4000&delay=1000"/>
<marshal>
<custom ref="myCustomDataFormat"/>
</marshal>
<to uri="file:C:/test2"/>
</route>
</camelContext>
</beans>
But when I try to start Camel, I get the following nasty error:
org.springframework.beans.ConversionNotSupportedException: Failed to convert value of type 'com.test.CustomDataFormat' to required type 'org.apache.camel.model.DataFormatDefinition'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.test.CustomDataFormat] to required type [org.apache.camel.model.DataFormatDefinition]: no matching editors or conversion strategy found
My Data Format is defined as follows:
package com.test;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.camel.Exchange;
import org.apache.camel.spi.DataFormat;
public class CustomDataFormat implements DataFormat {
/* (non-Javadoc)
* #see org.apache.camel.spi.DataFormat#marshal(org.apache.camel.Exchange, java.lang.Object, java.io.OutputStream)
*/
#Override
public void marshal(Exchange exchange, Object graph, OutputStream stream)
throws Exception {
System.out.println("Marshal");
byte[] bytes = exchange.getContext().getTypeConverter().mandatoryConvertTo(byte[].class, graph);
stream.write(bytes);
}
/* (non-Javadoc)
* #see org.apache.camel.spi.DataFormat#unmarshal(org.apache.camel.Exchange, java.io.InputStream)
*/
#Override
public Object unmarshal(Exchange exchange, InputStream stream)
throws Exception {
System.out.println("Unmarshal");
byte[] bytes = exchange.getContext().getTypeConverter().mandatoryConvertTo(byte[].class, stream);
return bytes;
}
}
I know that my CustomDataFormat implementation is correct because I created the following test route in Java and it worked flawlessly
package com.test;
import org.apache.camel.spring.SpringRouteBuilder;
public class TestFormatRoute extends SpringRouteBuilder {
/* (non-Javadoc)
* #see org.apache.camel.builder.RouteBuilder#configure()
*/
#Override
public void configure() throws Exception {
from("file:C:/test?initialDelay=4000&delay=1000").unmarshal(new CustomDataFormat()).to("file:C:/test2");
}
}
What am I missing?
Thanks
Update
After letting Camel completely start up after receiving this error I found to my disbelief that my custom data format actually does work in the route that I created. I'm not sure what process is attempting to parse my custom data format and failing but it is apparently not the same process parsing the data format to put into my route.
This solves the functional requirement of the data format, but it does not explain why I am receiving this error.
I have also confirmed that it was not the name of my data format (CustomDataFormat) that was causing the issue. Renaming my DataFormat to a unique name (MerlinDataFormat) did not fix the error.
I still would like to know why I am receiving this error since large blocks of ugly red errors in my console and log files aren't exactly appealing.
Thanks again.
It turned out to be a pretty simple solution (and one that I admit should have been easy to see). There are actually two ways to go about solving this issue, one of them using only spring and one of them requiring an additional java class.
Solution 1
Create a new class extending DataFormatDefinition which has the same properties as your custom DataFormat. Override the configureDataFormat() method to set all of the properties of the underlying DataFormat. Add constructor(s) to set the underlying DataFormat as an instance of your CustomDataFormat. Now you should be able to create an instance of your DataFormatDefinition in spring and reference it when marshaling or unmarshaling.
Solution 2 (Quick & Dirty)
In spring, create a new DataFormatDefinition bean and set it's dataFormat property as a reference to your DataFormat spring bean. Now you should be able to reference your DataFormatDefinition bean when marshaling or unmarshaling.
Not really sure what's wrong with your example, it seems just fine. Can you post your code for the data format? Are you implementing org.apache.camel.spi.DataFormat correctly?
I just set up this example with Camel 2.9.2 and it works like a charm. The Custom data format is the one from Camel documentation/source code.
<bean id="mySweetDf" class="com.example.MySweetDf"/>
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="file:C:/temp/test?initialDelay=4000&delay=1000"/>
<marshal>
<custom ref="mySweetDf"/>
</marshal>
<convertBodyTo type="java.lang.String"/>
<to uri="file:C:/temp/test2"/>
</route>
</camelContext>
data format java file:
package com.example;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.camel.Exchange;
import org.apache.camel.spi.DataFormat;
public class MySweetDf implements DataFormat {
public void marshal(Exchange exchange, Object graph, OutputStream stream) throws Exception {
byte[] bytes = exchange.getContext().getTypeConverter().mandatoryConvertTo(byte[].class, graph);
String body = reverseBytes(bytes);
stream.write(body.getBytes());
}
public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
byte[] bytes = exchange.getContext().getTypeConverter().mandatoryConvertTo(byte[].class, stream);
String body = reverseBytes(bytes);
return body;
}
private String reverseBytes(byte[] data) {
StringBuilder sb = new StringBuilder(data.length);
for (int i = data.length - 1; i >= 0; i--) {
char ch = (char) data[i];
sb.append(ch);
}
return sb.toString();
}
}
UPDATE
Just tried you code. Seems to work as well. Created a fresh camel 2.9.2 project via mvn archetype 168: remote -> org.apache.camel.archetypes:camel-archetype-spring (Creates a new Camel project with added Spring DSL support.). This does only include camel-core and camel-spring dependencies, nothing else.
Then replaced camel-context.xml with your xml and added your data format code in the java directory. A run with "mvn camel:run" copied the file and printed "marshal" in the log.
[pache.camel.spring.Main.main()] SpringCamelContext INFO Route: route1 started and consuming from: Endpoint[file://C:/test?delay=1000&initialDelay=4000]
[pache.camel.spring.Main.main()] SpringCamelContext INFO Total 1 routes, of which 1 is started.
[pache.camel.spring.Main.main()] SpringCamelContext INFO Apache Camel 2.9.2 (CamelContext: camel-1) started in 0.808 seconds
Marshal
Are you sure you have all dependencies setup correctly and not some .jar file that messes things up with Data formats?
UPDATE2
Okay, I think I have an idea what it is:
http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/model/dataformat/CustomDataFormat.html
Camel already have a class named as your data format. You should try rename it to something else. CustomDataFormat extends org.apache.camel.model.DataFormatDefinition which is referred to in your error. Java should handle this, since it's two different namespaces, but there might be some issue in your project setup that causes this conflict. Try to rename the data format and see if that solves the problem.
I too was facing the same issue with camel 2.10.0. If you provide the ref with an instance of type org.apache.camel.model.DataFormatDefinition everything works fine!! I can see two classes for xmljson conversion --> XmlJsonDataFormat implementing both DataFormat and DataFormatDefinition.
I solved the same issue that I too was facing.
Implemented a class extending DataFormatDefintion - which in it's configureDataFormat method sets injectable properties for the class that extends DataFormat (in your case this is CustomDataFormat).
I used XmlJson conversion as a template to solve.

Bypassing ViewResolver using #ResponseBody & Method Converters for JSON and XML only works for JSON

I'm creating a RESTful API that returns JSON or XML depending on the Accept header (application/json vs text/xml). I have this working fine for JSON but can't seem to get it working when for XML. I am testing using the Poster plugin client for Firefox.
I was under the impression that I just needed to add the Jackson and JAXB libraries to the app's classpath. Again, it works for JSON but not XML.
Originally I was getting 406 error when sending the Accept "text/xml" header. Then I added #XmlRootElement(name="contact") to my entity and now I'm getting a 500 error. Should I need to put #XmlRootElement on every entity?
Although the response is a 500 error, I don't see any errors reported in the console. I'm testing in Eclipse running Tomcat 7. Shouldn't i see some error in the console when i receive a 500 error?
My "mvc-dispatcher-servlet.xml" has <mvc:annotation-driven />
Here's the relevant code from my controller:
#Controller
#RequestMapping("/contacts")
public class ContactsController {
#Autowired
ContactsService contactsService;
#RequestMapping(value="/{id}",
method=RequestMethod.GET,
headers = {"Accept=application/json, text/xml"})
public #ResponseBody Contact getContact(#PathVariable("id") int id) {
Contact queryContact = new Contact(id);
Contact result = contactsService.getContact(queryContact);
return result;
}
}
The "mvc-dispatcher-servlet.xml" is really simple. Do I need anything other than:
<context:component-scan base-package="contactsapp.web.controller" />
<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/"/>
I'm using Spring 3.1 and the following:
<dependency org="com.sun.xml.bind" name="jaxb-impl" rev="2.2.5-b10" conf="runtime->default"/>
<dependency org="org.codehaus.jackson" name="jackson-mapper-asl" rev="1.7.1" conf="runtime->default"/>
You should put
#XmlRootElement on Contact class to tell jackson how to parse.
It turns out I had it configured correctly. Once I enabled more verbose logging I realized I had circular dependencies in my entity classes and had to add #XmlTransient on those fields

using ServletContext and ServletConfig in scriptlets and EL

I tried to run the following lines.
<%=application.getInitParameter("tagline")%>
<br />
<%=config.getInitParameter("admincontact")%>
${initParam.tagline}
<br />
${pageContext.servletConfig.initParameter("admincontact")}
And my web.xml is
<servlet>
<jsp-file>/index.jsp</jsp-file>
<init-param>
<param-name>admincontact</param-name>
<param-value>8939302763</param-value>
</init-param>
</servlet>
<context-param>
<param-name>tagline</param-name>
<param-value>Each one Plant one</param-value>
I get a exception at
${pageContext.servletConfig.initParameter("admincontact")}
and null value for
<%=config.getInitParameter("admincontact")%>.
Regards,
John
There is an FAQ on JavaRanch about this.
It states the following;
How to access servlet init parameters using EL?
You cannot use the following syntax to access servlet init parameters:
${pageContext.servletConfig.initParameter.name}
You cannot get Servlet init parameters using this technique. The
getInitParameter(java.lang.String name) does not fit in this case,
because it requires some arguments.
According to the JavaBean spec, the property has getter & setter
methods in the form
public type1 getXXX() -- WITH NO ARGUMENTS.
public void setXXX(type1)
Now consider the pageContext as bean Object. The
PageContext class has methods like getServletConfig(), getRequest(),
getSession() etc. You can access these like pageContext.page,
pageContext.request etc in EL.
ServletContext object has a couple of methods like getMajorVersion(),
getMinorVersion() with no args. so we can access these methods
treating it as properties to sevletContext bean as
pageContext.servletContext.majorVersion and
pageContext.servletContext.minorVersion.
If you want to access Servlet init parameters using EL, then it is
better to create a Map of the init parameters for the servlet and
place it in the request as a scoped variable -- let's say
initParameters. You would then be able to obtain any param by name
with ${requestScope.initParameters.name}.
NOTE:
We can access context init parameters with ${initParam.name}
In addition to Mr Moose's answer, I have found this solution that uses EL defining a custom tag.
It worked in my case.
Here the link
Basically you have to create a Java class like this:
package example.customTags;
import javax.servlet.jsp.JspPage;
public class MyFunctions {
public static String getJspInitParameter(JspPage page, String param){
return page.getServletConfig().getInitParameter(param);
}
}
Create a tld file like this (my filepath is WEB-INF/myTags/customTags.tld):
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>Functions</short-name>
<function>
<name>getJspInitParameter</name>
<function-class>example.customTags.MyFunctions</function-class>
<function-signature>
java.lang.String getJspInitParameter(javax.servlet.jsp.JspPage, java.lang.String)
</function-signature>
</function>
</taglib>
And use it in your JSP like this:
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%# taglib prefix="my" uri="../WEB-INF/myTags/customTags.tld"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Example</title>
</head>
<body>
<c:out value="${my:getJspInitParameter(pageContext.page, 'admincontact')}"/>
</body>
</html>

Resources