How to extract java method parameters with regex - java

I'm writing a Python script to parse Java classes from a backend service in order to extract necessary information. One of the things I need is to extract the request parameter from a java method.
public\s+[\w<>\[\]]+\s+(\w+)\s*\(([^{]+)(^(#ApiParam(.*)\))|^(#PathParam(.*))|^(#QueryParam(.*))|(#\w+\s+)?)((\w+)\s+(\w+))
Is what I got so far... It already gives me the method parameters in the brackets () however I cannot filter out the #ApiParam and #QueryParam annotations.
/*Some annotations*/
public PortfolioSuggestion calculatePortfolioSuggestion(
#ApiParam(required = true,
value = "Request containing the answers which were answered by the user and an\n" +
"investment for which suggestion should be calculated")
#Valid #NotNull PortfolioSuggestionRequest portfolioSuggestionRequest,
#ApiParam(value = "The optional product key")
#QueryParam("product") ProductType productType)
throws SuggestionsCalculationException {
The request parameter is always the first parameter which is not annotated with #ApiParam or #QueryParam. In this case my target would be PortfolioSuggestionRequest and portfolioSuggestionRequest. The annotations #Valid and #NotNull are always optional and could be omitted

TL;DR : Regexp are not powerful enough for your usecase
Any regexp is equivalent to a Deterministic finite automaton.
Regexps are not always suited to parse code. It sometimes requires to have a Pushdown automaton which regexp doesn't provide. You might want to look into ANTLR which is full feature language parser.
See this question for a similar example.
Here is some github repo aiming at parsing java using ANTLR.

Related

How to map dynamic query parameters in Spring Boot RestController

Is it possible to map query parameters with dynamic names using Spring Boot? I would like to map parameters such as these:
/products?filter[name]=foo
/products?filter[length]=10
/products?filter[width]=5
I could do something like this, but it would involve having to know every possible filter, and I would like it to be dynamic:
#RestController
public class ProductsController {
#GetMapping("/products")
public String products(
#RequestParam(name = "filter[name]") String name,
#RequestParam(name = "filter[length]") String length,
#RequestParam(name = "filter[width]") String width
) {
//
}
}
If possible, I'm looking for something that will allow the user to define any number of possible filter values, and for those to be mapped as a HashMap by Spring Boot.
#RestController
public class ProductsController {
#GetMapping("/products")
public String products(
#RequestParam(name = "filter[*]") HashMap<String, String> filters
) {
filters.get("name");
filters.get("length");
filters.get("width");
}
}
An answer posted on this question suggests using #RequestParam Map<String, String> parameters, however this will capture all query parameters, not only those matching filter[*].
Does matrix variables work for you? If I understand you correctly, can be like this:
// GET /products/filters;name=foo;length=100
#GetMapping("/products/filters")
public void products(
#MatrixVariable MultiValueMap matrixVars) {
// matrixVars: ["name" : "foo", "length" : 100]
}
This seems like a solvable problem. The solutions are not ideal far as I know, but there are ways.
A previous attempt seemed bent on finding a perfect solution where the entire composition of the filter was known in-transit.
Spring MVC populate
The entirety of the dynamic criteria that user defines can be transmitted with some basic scheme you define, as one key=value parameter from the client, then decomposed into its elements once it is received.
You could also send two parameters: "fields" and "values", where the lists of each are encoded in there respectively, with some cautious delimiter of your choosing (could be an encoded special character that the user cannot physically type, perhaps).
You still need, as with everything other approach where the client side is submitting criteria (like filter criteria), full protection from any malicious use of the parameters, just as the client trying to embed SQL criteria in them (SQL Injection).
But so long as the client code follows the agreed syntax, you can receive any number of dynamic parameters from them in one shot.
Client:
/products?filter=field1--value1||field2--value2||field3--value3...
That is a simplified example showing delimiters that are too easy to "break", but the idea is some simple, even fully readable (no harm in doing so) scheme just for the purpose of packing your field names and values together for easy transit.
Server:
#RequestMapping(value = "/products", method = RequestMethod.GET)
public String doTheStuff(#RequestParam(value = "filter") String encodedFilter) {
.. decompose the filter here, filter everything they've sent for disallowed characters etc.

How can I make Swagger read SpringMVC annotations

While reviewing a piece of code I encountered a heavily annotated function, which included something along the lines of
#ApiParam(value = "order number", required = false) #RequestParam(value = "order", required = true)
required = false vs. requires = true looks very suspicious, it's probably a bug. The repetition in the annotations is an obvious cause for such bugs. Why would Swagger not be able to simply read the #RequestParam annotation, making the #ApiParam annotation obsolete, or at least optional?
How would I do this elegantly?
Are you using the latest spring-fox? According to the Docs, you'll only need to use the #ApiXX when the behaviour/model cannot be extracted from MVC/Jackson annotations:
1.2. Goals
Philosophically, we want to discourage using (swagger-core) annotations that are not material to the service description at runtime. For e.g. the jackson annotations should always trump or have more weight than #ApiModelProperty or for e.g. #NotNull or specifying #RequestParam#required should always win. Annotations are to to be used only to supplement documentation or override/tweak the resulting spec in cases where its not possible to infer service/schema characteristics.
So even though the #ApiParam specifies a conflicting value for required, the generated api-docs by springfox will use the #RequestParam value.

Rest API - spring controllers and resources

I am writing a rest API which is quite simple, this is my first attempt and I will be using spring framework.
The test app only deals with products, categories and types . A product has a type, a category has many types and a product can also have multiple categories which it can fit into so I am wondering if I should create a spring controller for each.
If I did that then would it be possible to get a product back when calling through the category controller and would this be o.k?
I mean something like this:
/categories/{category_id}/types/{type_id}/products
To me this would filter by category, then a type and get all products for the type, or is this not restful?
Rest patterns should be simple and not layered.
If you wish to retrieve things, they should be straightforward like:
/categories/{category_id}
/products/{product_id}
/types/{type_id}
For filtering, you should make use of query string instead of url path because url path cares about order/hierarchy, whereas filtering should not be concerned with order.
Yes you can. This API looks fine to me. And if you are looking for the implementation see below.
The function below works just fine
#RequestMapping(value="/categories/{category_id}/types/{type_id}/products", method = RequestMethod.GET)
#ResponseBody
public void test(
#PathVariable String category_id,
#PathVariable String type_id)
{
}
If you need you can bind property editors for your category and type objects and pass them as objects to the function.
I think you should have a ProductController that can get products by 1 or more parameters. I would use query parameters instead of path params, since path params will get confusing esp. when you query for multiple categories or types. So have a service like;
/product/list?category=a,b,c&type=abcd
/product/get/id=123 or /product/get/{id}
You can have controllers for categories & types which allow listing and create/update/delete (if supported) for them.
/category/get?id=123
/types/get?id=123
Most commonly you would model this as
/category/
/product/
/type/
(for POST, with trailing ID for PUT and DELETE) and then you can query (GET) the products and categories as follows
/product/?category_id=123
/product/?type_id=12
/category/?name=big+items
When you have a 1:1 relationship you could also consider combining category and type into a single entity. Perhaps the type is an attribute of the category instead, or vice versa.
Based on your specification,
/categories/{category_id}/types/{type_id}/products
{type_id} is really redundant because of the 1:1 relationship between category and type.
On the other hand,
/categories/{category_id}/products/
is fine, but lets you only search for one category at a time.
ps. "type" is often a reserved keyword and can lead to strange error messages

How would I specify a Hibernate “#Pattern” annotation using a regular expression from a .properties file or database

Situation: I would like to perform Hibernate Validation based upon user properties (to allow different validation rules for input based upon a user's account data) - I think it must be possible to use a .properties file to specify a particular regular expression, but I can't figure out what is wrong:
My current method of specifying a validation regex pulls that regex from a constant in a particular interface file (to keep everything together) and plugs it in as a constant in an #Pattern() annotation for each variable - e.g. for the variable workPhone:
#Column(name = "WORK_PHONE")
#NotEmpty(message = "{ContactInfo.workPhone.notEmpty}")
#Pattern(regexp = PHONE_NUMBER_PATTERN_SL, message = "{ContactInfo.workPhone.regexp.msg}")
#Size(max = 10, message = "{ContactInfo.workPhone.size}")
protected String workPhone;
...where the regex is stored in the static final String PHONE_NUMBER_PATTERN_SL and all the {ContactInfo.workPhone...} calls come from a .properties file:
ContactInfo.workPhone.notEmpty=Please enter your phone number.
ContactInfo.workPhone.regexp.msg=Invalid characters entered in phone. Use this format XXX-XXX-XXXX.
ContactInfo.workPhone.size=Phone can not be longer than 10 digits.
Unfortunately, this arrangement makes the validation pattern application-wide (compiled), as I can't figure a way to change it for a different user in a different company, location, employment position, etc. To make it possible to differentiate based upon this info, I'd like to also store the regex in the properties file, and I try to include it this way:
ContactInfo.workPhone.regexp=\d{3}-\d{3}-\d{4}
while including the reference in the annotation from the third line in the first code listing:
#Pattern(regexp = "{ContactInfo.workPhone.regexp}", message = "{ContactInfo.workPhone.regexp.msg}")
I would then switch out the properties files for different occasions, such as to allow/require a non-U.S. telephone number format.
Question: Is it possible to do what I want to do? Is there a better way to specify the pattern (which might allow even a database call instead of a properties file)?
Additionally, I'm not the best at this (as I'm taking over from another developer), so if someone could merely point me to a focused resource concerning the use of the #Pattern annotation or other Hibernate regex validation markup, then that might give me all the info I need.
TL;DR: Is it possible to use a dynamically-set or modified value for the expression used in Hibernate Pattern Validation rather than a predefined and precompiled constant?
Within annotations you can only refer to constant expressions, so loading values from a property file or database wouldn't work here.
You could use the API for dynamic constraint declaration introduced in Hibernate Validator 4.2 which allows to define constraints at runtime. Your example might look like that:
String dynamicPattern = ...;
ConstraintMapping mapping = new ConstraintMapping();
mapping.type( ContactInfo.class )
.property( "workPhone", FIELD )
.constraint( new PatternDef().regexp( dynamicPattern ) );
HibernateValidatorConfiguration config =
Validation.byProvider( HibernateValidator.class ).configure();
config.addMapping( mapping );
Validator validator = config.buildValidatorFactory().getValidator();

Complexe RESTful GET queries

I understand how to do queries like GET http://localhost:8080/rest_mysql/books/1 and pull with an ID, in this case "1", but lets say you wanted to search for a book with 2 variablies instead of 1. Can this still be done via GET?
You could change the identifier in your URL to allow a delimited list of ids:
GET /books/1+2
This would keep your URL nice and neat, and adhere to the spirit of REST, wherein the URL identifies a resource. Another benefit is that you could have a single binding which would handle an arbitrary number of ids in the URL.
#GET
#Produces("application/json")
#Path("/books/{ids}")
public Books getBooks(#PathParam("ids") String ids) {
Books books = new Books();
for (String id: ids.split("+")) {
books.add(bookRepository.findById(id))
}
return books;
}
This method could handle multiple scenarios:
GET /books/1
GET /books/2
GET /books/1+2
GET /books/1+2+3
We can talk about 2 kind of queries
simple queries constructed by the server
These queries are constructed by the server and passed to the URI, so the client has nothing to do with them, because it never parses the URIs. (REST clients follow links and use semantic annotations of links, for example link relations to decide what link to choose. - HATEOAS constraint) So you can use any solution you want, there are no constraints about how to build an URI. (URIs have to identify resources, so one URI cannot belong to multiple resources. URIs are mapped to resources and not operations, so if you want to have human readable URIs, then they will probably contain only nouns and not verbs.)
ad-hoc queries constructed by the client
By this kind of queries you have to use URI templates and annotate the params with some semantics (probably by using an application dependent vocab). If you exceed the capabilities of URI templates, then you need a standard query language (e.g. SQL) and a standard description format for your query constraints (currently not available afaik, but can be an extended template language annotated with RDF semantics).
In your case it is not clear what you want. One thing is sure, it is a simple query constructed by the server.
You are talking about a single book identified with 2 parameters. In this case the result will contain the representation of a single item resource and you can have something like this: /books/x:1+y:2 or /books/x:1/y:2 or /books?x=1&y=2. But identifying a book with 2 params does not make sense to me.
If you want to get multiple books in the response, then we are talking about map reducing a collection resource. You can use just the same URIs as mentioned by the single item resource: /books/x:1+y:2 or /books/x:1/y:2 or /books?x=1&y=2.
You can have a convention about how to distinguish collections and items, for example /books?x=1&y=2 can mean map reducing a collection and /books/x:1+y:2 can mean identifying a single item. But that part depends on you. Ofc it is better to have a convention about this, because it is easier to write the URI generation and routing logic on the server.
Nevermind. I found my answer with the folliwing code:
#GET
#Produces("application/json")
#Path("/network/{id: [0-9]+}/{nid}")
public User getUserByNetworkId(#PathParam("id") int id, #PathParam("nid") String networkId) {
Query q = em.createQuery("SELECT u FROM User u WHERE u.networkId = :id AND u.networkUserId = :nid");
q.setParameter("id", id);
q.setParameter("nid", networkId);
return (User) q.getSingleResult();
}
Common approach is to pass the arguments as query string parameters... but you could have them come in as part of the url instead.
e.g. books/search/arg1/arg2
Personally I prefer the query string approach.

Resources