#FormParam case sensitivity in Java Jersey - java

I am using Java with Jersey 1.16.
Is the name of a #FormParam parameter case sensitive?
Can I somehow force it to be NON case sensitive? (hopefully in some global way).

You could filter the requests:
public class CaseFilter implements ContainerRequestFilter {
#Override
public ContainerRequest filter(ContainerRequest request) {
for (Entry<String, List<String>> entry: request.getFormParameters().entrySet()) {
request.getFormParameters().put(entry.getKey().toLowerCase(), entry.getValue());
}
return request;
}
}
And update web.xml accordingly:
...
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>org.example.CaseFilter</param-value>
</init-param>
...

Related

In JAX-RS, entire JSON string is being posted

I have a simple Jersey POST method that accepts JSON. I am using SOAP UI to test, using POST and media type application/JSON.
Within the request body I have JSON:
{
email:"test"
}
When I test this, the string I expect to come into the service as test actually comes in as the entire JSON string. Not sure what's wrong here, it should work according to the docs.
#POST
#Path("/TEST")
#Consumes(MediaType.APPLICATION_JSON)
public Response testJaxRs(String email){
// email = "{
// email:"test"
// }"
return Response.ok().build();
}
If you do not want to deserialize it to a bean, then you can accept the post body as a map of key-value pairs. For example:
public Response testJaxRs(Map<String, String> body) {
body.get("email") // "test"
...
You need a bean
public class Email{
private String email;
//getters&setters
}
public Response testJaxRs(Email emailBean){
Note that you need to add the dependencies to decode json. e.g Jackson and add this mapping to jersey servlet in web.xml> See full example here: https://www.mkyong.com/webservices/jax-rs/json-example-with-jersey-jackson/
<web-app ...>
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.yourpackage</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
If you're using Jersey 1.x, then to receive your Json as an object you need to declare the POJO and annotate it with javax.xml.bind.annotation.XmlRootElement:
#XmlRootElement
public class EmailTest{
String email;
public String getEmail(){
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
}
Then you have to use this class in your controller:
#POST
#Path("/TEST")
#Consumes(MediaType.APPLICATION_JSON)
public Response testJaxRs(Email email){
System.out.println(email.getEmail()); // prints "test"
return Response.ok().build();
}
Finally you've to add com.sun.jersey.config.property.packages as <init-param> of your servlet adding the package or packages (separated by ,) pointing to your controller packages. For example in your web.xml:
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>org.app.controllers</param-value>
</init-param>

Swagger - Extending SwaggerSpecFilter

I'm trying to write my own Swagger API Filter to hide certain things from appearing in the API. I think I have a pretty good idea of what I should be doing but I must be missing something in the details.
I'm using Swagger Core 1.3.10 and Spring 3.1. Here's some of what I have now:
SwaggerApiAuthorizationFilter
public class SwaggerApiAuthorizationFilter implements SwaggerSpecFilter {
private final static Logger logger = LoggerFactory.getLogger(SwaggerApiAuthorizationFilter.class);
#Override
public boolean isOperationAllowed(Operation operation, ApiDescription api, Map<String, List<String>> params,
Map<String, String> cookies, Map<String, List<String>> headers) {
return true;
}
#Override
public boolean isParamAllowed(Parameter parameter, Operation operation, ApiDescription api, Map<String, List<String>> params,
Map<String, String> cookies, Map<String, List<String>> headers) {
// do not allow the documentation to be generated on parameters that have their access set to "internal"
if (parameter.paramAccess().isDefined() && parameter.paramAccess().get().equalsIgnoreCase("internal")) {
logger.debug("The following parameter has been hidden from the Swagger API documentation: " + parameter.name());
return false;
} else {
return true;
}
}
}
SwaggerServlet
public class SwaggerServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private final static Logger logger = LoggerFactory.getLogger(SwaggerServlet.class);
BeanConfig beanConfig;
SwaggerApiAuthorizationFilter swaggerApiAuthorizationFilter;
public void setBeanConfig(BeanConfig beanConfig) {
this.beanConfig = beanConfig;
}
public void setSwaggerApiAuthorizationFilter(SwaggerApiAuthorizationFilter swaggerApiAuthorizationFilter) {
this.swaggerApiAuthorizationFilter = swaggerApiAuthorizationFilter;
}
#Override
public void init(ServletConfig servletConfig) throws ServletException {
try {
super.init(servletConfig);
beanConfig.setBasePath("/mbl/services");
beanConfig.setVersion("1.0");
beanConfig.setResourcePackage("com.whatever.resources");
beanConfig.setScan(true);
FilterFactory.setFilter(swaggerApiAuthorizationFilter);
logger.debug("The Swagger servlet has been initialized");
} catch (Exception e) {
e.printStackTrace();
}
}
}
spring config file
<!-- Swagger Configuration and Providers -->
<bean id="beanConfig" class="com.wordnik.swagger.jaxrs.config.BeanConfig">
<property name="title" value="Java API"/>
<property name="version" value="1.0" />
<property name="basePath" value="/mbl/services"/>
<property name="resourcePackage" value="com.whatever.resources"/>
<property name="scan" value="true"/>
</bean>
<bean id="swaggerApiAuthorizationFilter" class="com.whatever.util.SwaggerApiAuthorizationFilter" />
web.xml
<!-- Enabling Swagger servlet -->
<servlet>
<servlet-name>Swagger Servlet</servlet-name>
<servlet-class>com.whatever.web.SwaggerServlet</servlet-class>
<init-param>
<param-name>swagger.filter</param-name>
<param-value>com.whatever.util.SwaggerApiAuthorizationFilter</param-value>
</init-param>
<load-on-startup>-1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Swagger Servlet</servlet-name>
<url-pattern>/api-docs</url-pattern>
</servlet-mapping>
Resource class
public Response getUserInfo(
#Context HttpHeaders headers,
#ApiParam(name="brand", access="internal") #CookieParam(value = "brand") String brand) {
It appears that my SwaggerApiAuthorizationFilter isn't even being called. My guess is that something is wrong in my configuration either in the web.xml or the SwaggerServlet. Does anyone see anything above that looks incorrect or does anyone have any ideas?
I've just used the filter successfully. I had problems to make filter function properly. The problem was that there was a problem to find my filter's implemention class. When I changed the package to a place where swagger's class could access, everything funtioned correctly. Next, I just had to implement my logic on my filter class. My filter class implemented the interface SwaggerSpecFilter too. Best regards.
I'm using DefaultJaxrsConfig:
<servlet>
<servlet-name>Jersey2Config</servlet-name>
<servlet-class>io.swagger.jaxrs.config.DefaultJaxrsConfig</servlet-class>
<init-param>
<param-name>api.version</param-name>
<param-value>1.0.0</param-value>
</init-param>
<init-param>
<param-name>swagger.api.basepath</param-name>
<param-value>/my-service/service/</param-value>
</init-param>
<init-param>
<param-name>swagger.filter</param-name>
<param-value>mypackage.SwaggerFilter</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
I'm just guessing but I think you need to implement Filter as well as the SwaggerSpecFilter interface instead of extending HttpServlet (looking at the source it does not appear SwaggerSpecFilter extends Filter as one would expect), then configure it as a filter in your web.xml instead of a servlet. It would be something like this:
<filter>
<filter-name>Swagger Filter</filter-name>
<filter-class>com.whatever.util.SwaggerApiAuthorizationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Swagger Filter</filter-name>
<url-pattern>/api-docs</url-pattern>
</filter-mapping>
Again, not sure if this will work but just a guess off the top of my head.

How to retrieve ServletRequest using Jersey and Java EE 5

I'm working on creating a security library that will be used by several RESTful clients. I'm using Java EE 5, Jersey 1.17 and Maven. The clients will use my library to call a third party app using a token. The third party app will then return all the information it has on that token, like expiration, scope and userId.
My idea is to make a filter that will check if there is an Authorization header, and if that's so, it calls the third party app. If the third party app validates the token and returns the token's info, I need to return that information, stored in a TokenInformation object, back to the resources. In a previous post, someone said that I could do this:
public class MyFilter implements Filter{
#Override
public void doFilter(final ServletRequest request,
final ServletResponse response,
final FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String header = req.getHeader("Authorization");
TokenInformation info = new TokenInformation();
info = buildInfo(info);
if (true) {
request.setAttribute("auth", info);
chain.doFilter(request, response);
} else {
handleError(response);
}
}
}
So, by sending the TokenInformation object to the request as an additional attribute, I would be able to retrieve it later in the resource classes. The thing is that I'm using Java EE 5, and I didn't realize that I couldn't use the #Context annotation to inject the ServletRequest object. How can I access the ServletRequest object again from a resource class, so that I can access the TokenInformation object in, for example, the DAO?
The way I'm using jersey is by doing this in my web.xml:
<servlet>
<servlet-name>Security API</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.ni.apps.engineering.securitylibrary.resources.SecurityResource</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Security API</servlet-name>
<url-pattern>/1/*</url-pattern>
</servlet-mapping>
The SecurityResource class has this:
public class SecurityResource extends Application{
public static final String SUPPORTED_REPRESENTATIONS = MediaType.APPLICATION_XML
+ "," + MediaType.APPLICATION_JSON;
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>();
set.add(Security.class);
return set;
}
}
The Security class has this:
#Path("")
public class Security implements ISecurity{
#Override
public Response get(String upId) {
String test = "";
try{
TokenInformation tI = (TokenInformation) HttpServletRequestWrapper.
test = "test1";
}catch(Exception e){
System.out.println(e.getMessage());
}
return null;
}
}
You don't have to access ServletRequest at Dao layer.
In Servlet you can get ServletRequest object and you can pass the value to Dao layer.
If you really want to access then pass ServletRequest object to Dao layer by reference.
<servlet-name>Security API</servlet-name>
<servlet-class>com.packagename.MyServlet</servlet-class>
public MyServlet extends com.sun.jersey.spi.container.servlet.ServletContainer{}
You can extend jersey servlet and you can initialize Servlet with Application Class by programatically.
In MyServlet you can reach the request object.
Servlet Information :
https://jersey.java.net/apidocs/1.17/jersey/com/sun/jersey/spi/container/servlet/ServletContainer.html

Geolocation in Java Jersey

I would like to know if it is possible to call a method for every matching HTTP request.
My case:
I need to send geolocation data in http headers, I send the request, it matches a defined operation and at the same time my geolocation is updated.
I can easily replicate a method call for each method in each class, but I would rather find a more adequate way to solve this problem.
Thank you for reading.
What you are looking for is a Jersey ResponseFilter. Here is a very simple example that adds a static header to every outgoing request:
package my.package;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
public class SimpleFilter implements ContainerResponseFilter
{
private static final String HEADER = "MyHeader";
public SimpleFilter()
{
}
#Override
public ContainerResponse filter(final ContainerRequest request, final ContainerResponse response)
{
response.getHttpHeaders().add(HEADER, "MyValue");
return response;
}
}
You can access various information through the request and response parameters to the filter method.
You will need to add the filter through your web.xml file to activate it:
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>my.package.SimpleFilter</param-value>
</init-param>

How to add filters to servlet without modifying web.xml

I'd like the ability to modify/configure filters in a different way than web.xml. Here is a static configuration of 2 filters. I'd like the ability to have one filter statically configured and allow that filter to load additional filters. I just wanted to know if anyone knows of lib that already has this.
Using Servlet API 2.5
<web-app>
...
<filter>
<filter-name>MyFilter1</filter-name>
<filter-class>com.me.MyFilter1</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
<filter>
<filter-name>MyFilter2</filter-name>
<filter-class>com.me.MyFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
I've seen this done in Guice with GuiceFilter where the Filters are configured at runtime.
Just do the same job as the container already does. I.e. reinvent the wheel of the chain of responsibility design pattern as is under the covers been used by servlet filters.
public class GodFilter implements Filter {
private Map<Pattern, Filter> filters = new LinkedHashMap<Pattern, Filter>();
#Override
public void init(FilterConfig config) throws ServletException {
Filter1 filter1 = new Filter1();
filter1.init(config);
filters.put(new Pattern("/foo/*"), filter1);
Filter2 filter2 = new Filter2();
filter2.init(config);
filters.put(new Pattern("*.bar"), filter2);
// ...
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest hsr = (HttpServletRequest) request;
String path = hsr.getRequestURI().substring(hsr.getContextPath().length());
GodFilterChain godChain = new GodFilterChain(chain);
for (Entry<Pattern, Filter> entry : filters.entrySet()) {
if (entry.getKey().matches(path)) {
godChain.addFilter(entry.getValue());
}
}
godChain.doFilter(request, response);
}
#Override
public void destroy() {
for (Filter filter : filters.values()) {
filter.destroy();
}
}
}
with those little helper classes (which can if necessary be made private static nested classes of the above GodFilter):
public class Pattern {
private int position;
private String url;
public Pattern(String url) {
this.position = url.startsWith("*") ? 1
: url.endsWith("*") ? -1
: 0;
this.url = url.replaceAll("/?\\*", "");
}
public boolean matches(String path) {
return (position == -1) ? path.startsWith(url)
: (position == 1) ? path.endsWith(url)
: path.equals(url);
}
}
and
public class GodFilterChain implements FilterChain {
private FilterChain chain;
private List<Filter> filters = new ArrayList<Filter>();
private Iterator<Filter> iterator;
public GodFilterChain(FilterChain chain) {
this.chain = chain;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if (iterator == null) {
iterator = filters.iterator();
}
if (iterator.hasNext()) {
iterator.next().doFilter(request, response, this);
} else {
chain.doFilter(request, response);
}
}
public void addFilter(Filter filter) {
if (iterator != null) {
throw new IllegalStateException();
}
filters.add(filter);
}
}
You could if necessary also feed a XML config file with all possible filters so that you end up with easier configuration. You could use reflection to create filters in init() of your GodFilter.
Oh nevermind, that's what the web.xml and the container already is doing...
Servlet 3.0 has the #WebFilter annotation to define a filter. No need to declare it in web.xml anymore.
But loading a filter from a filter is not supported. You could implement it yourself: it's "just" the chain of responsibility pattern, but why would you?
It can be achieved in easy steps, even for pre-3.0 Servlet spec:
Add a filter containing a static & ordered collection of Classes (chain).
Map the filter to intercept every traffic.
Manipulate the order & existence of your helper classes (those will be called privately by your filter upon interception of traffic) in the chain.
Ref: Xstream uses same kind of pattern for Serializer, well not with Servlet/Filter though. :)
I personally like the #WebFilter annotation to register servlet filters.
But another solution is to add the filter at runtime using the ServletContext's addFilter function.
Implement ServletContextListener; something like:
public class MyContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent ce) {
ServletContext servletContext = ce.getServletContext();
// you can even conditionally add this
servletContext.addFilter("My filter 1", MyFilter1.class)
.addMappingForUrlPatterns(allOf(DispatcherType.class), false, "/*");
}
}
Register listener:
<listener>
<listener-class>com.me.MyContextListener</listener-class>
</listener>
And of course you need to implement a Filter. But in your question you already refer to an example filter 'MyFilter1'.

Categories