How to get values by name with JAX-RS(JSR339) - java

Colleagues in my office are developping a web system with JAX-RS(JSR339).
I need to get values by name(string) and I asked them to. But they have few idea.
I'm quite new to JAX-RS and googled it and I learned that
JAX-RS injects values to variables by annotations like
#Path("/sample")
public interface SampleResource {
#GET
#Path("/hello/{message}")
String sayHello(#PathParam("message") String message);
}
However I want to get values by name at runtime like
#Path("/sample")
public interface SampleResource {
String name = "message"; // dynamic value
#GET
#Path("/hello/{" + name + "}")
String sayHello(#PathParam(name) String message);
}
Perhaps this is a wrong code. My question is how to get values by name like the example above.
(I'm afraid the sample codes aren't correct ones but I hope you grasp my idea and concerns. Thanks.)

Try something like this.
Example of the bean which will be used as #BeanParam
public class MyBeanParam {
#PathParam("p")
private String pathParam;.
public String getPathParam() {
return pathParam;
}
}
Injection of MyBeanParam as a method parameter:
#GET
String sayHello(#BeanParam MyBeanParam beanParam, String entity){
final String pathParam = beanParam.getPathParam(); // contains injected path parameter "p"
...
}
OR
You can use UriInfo to get QueryParam. For example application see this

Related

How to have query string parameter(s) and field name(s) different

I have a controller which will have 3 query strings.
Instead of having 3 fields in controller, I am defining them in class.
public class PassengerInformation{
String travellerAddress;
String travellerAge;
String travellerName;
}
Now in controller , I am able to accept them
#GetMapping("/passenger-info)
public TravelInformation getPassengerInfo(PassengerInformation info){
//Call a service
}
Now, this works as expected, if I pass the query string as is. eg: /passenger-info?travellerAge=21.
But, How do I accept the query parameter names different to it's corresponding fieldName.
I should be able to call it as below:
/passenger-info?traveller_age=21&traveller_name=JohnWick&traveller_address=ST.
Try to add the following constructor to your class
public class PassengerInformation{
String travellerAddress;
String travellerAge;
String travellerName;
#ConstructorProperties({"traveller_address", "traveller_age", "traveller_name"})
public PassengerInformation(String travellerAddress, String travellerAge, String travellerName) {
this.travellerAddress = travellerAddress;
...
}
}
The best you can do by the default features without any customisation is to use #ConstructorProperties :
public class PassengerInformation {
String travellerAddress;
String travellerAge;
String travellerName;
#ConstructorProperties({ "traveller_address", "traveller_age", "traveller_name" })
public PassengerInformation(String travellerAddress, String travellerAge, String travellerName) {
this.travellerAddress = travellerAddress;
this.travellerAge = travellerAge;
this.travellerName = travellerName;
}
}
This behaviour is mentioned at the docs as follows :
The #ModelAttribute parameter instance (i.e PassengerInformation)
is sourced in one of the following ways:
Retrieved from the model where it may have been added by a
#ModelAttribute method.
Retrieved from the HTTP session if the model attribute was listed in
the class-level #SessionAttributes annotation.
Obtained through a Converter where the model attribute name matches
the name of a request value such as a path variable or a request
parameter (see next example).
Instantiated using its default constructor.
Instantiated through a “primary constructor” with arguments that match
to Servlet request parameters. Argument names are determined through
JavaBeans #ConstructorProperties or through runtime-retained parameter
names in the bytecode.
The caveat here is that you need to make sure there are no default constructor in the PassengerInformation :
public class PassengerInformation {
public PassengerInformation(){}
}

arguments for hasPermission in a generic controller

I am trying implement a generic controller class where each method has a structure similar to this:
#RequestMapping(value="cadastra")
#PreAuthorize("hasPermission(#user, 'cadastra_#this.class.name')")
public ModelAndView cadastra() throws InstantiationException, IllegalAccessException {
return new ModelAndView("privado/"+this.entity.getClass().getName()+"/cadastra", "command", this.entity.getClass().newInstance());
}
I am having trouble with the annotation PreAuthorize. the name for the permissionhave this structure: _. right now, I am getting a 403 Error when I try access the view mapped by the method. I also tried other variations like:
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.class.name)")
or
#PreAuthorize("hasPermission(#user, 'cadastra_#this.getClass().getName()')")
but with the same result. Anyone knows the right way to accomplish this?
UPDATE
I try call this function inside the methods from controller secured by this tag PreAuthorize:
private void expressionParser() {
System.out.println("expressionHandler()");
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("'cadastra_'+#this.class.name");
String message = (String) expression.getValue();
System.out.println("Message is " + message);
}
and when I run the application and open the view should be mapped by a method from controller, like this one:
#RequestMapping(value="cadastra")
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.class.name)")
public ModelAndView cadastra() throws InstantiationException, IllegalAccessException {
this.expressionParser();
return new ModelAndView("privado/"+this.entityClass.getName()+"/cadastra", "command", this.entityClass.newInstance());
}
No message is displayed on the console. So, I am thinking my application somehow aren't calling the methods from my generic controller. Am I right? If so, how I fix this?
My derived controllers follow this structure:
#Controller
#RequestMapping(value="usuario")
public class UsuarioController extends controller<Usuario> {
public UsuarioController() {
super(Usuario.class);
}
}
So you have difficulties with dynamic construction of permission name in the form of [methodName]_[classFullName] in SpEL expression.
See what SpEL documentation says about #this variable below
The variable #this is always defined and refers to the current evaluation object
(against which unqualified references are resolved).
Based on the documentation and a bit digging in the code the actual object the #this represents should be in your case an instance of org.springframework.security.access.expression.method.MethodSecurityExpressionRoot class. The class contains several helpful methods among others also getThis() method that returns the target object on which the secured method (a method annotated with #PreAuthorize) is being invoked.
Armed with this knowledge it should not be a big deal to construct the expression you require. In case of method named "cadastra", it should be as follows.
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.this.class.name)")
Hopefully it will also work correctly for secured methods inherited from a base class.
So, I solved this issue with this approach:
1) Adding a new method to my generic controller, where I return the name of the class:
public String getName() {
String expressao = entityClass.getName();
String nome_classe = new String();
StringTokenizer st = new StringTokenizer(expressao, ".");
while (st.hasMoreTokens()) {
nome_classe = st.nextToken();
}
return nome_classe;
}
2) Inside the annotation, I use the returned value by this method and concatenate the result with the constant string (using the notation described by the user #pgjecek in this topic):
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.this.name)")
and now it1s working perfectly.

How to serialize ANY Object into a URI?

My basic question: is there anything built that already does this automatically (doesn't have to be part of a popular library/package)? The main things I'm working with are Spring (MVC) and Jackson2.
I understand there are a few manual ways to do this:
Create a method in each class that serializes its specific properties into property=value& form (kind of stinks because it's a bunch of logic duplication, I feel).
Create a function that accepts an object, and uses reflection to dynamically read all the properties (I guess the getters), and build the string by getting each. I'm assuming this is how Jackson works for serialization/deserialization in general, but I really don't know.
Use some feature of Jackson to customly serialize the object. I've researched custom serializers, but it seems they are specific to a class (so I'd have to create one for each Class I'm trying to serialize), while I was hoping for a generic way. I'm just having trouble understanding how to apply one universally to objects. A few of the links:
http://techtraits.com/Programming/2011/11/20/using-custom-serializers-with-jackson/
http://wiki.fasterxml.com/JacksonHowToCustomSerializers
Use ObjectMapper.convertValue(object, HashMap.class);, iterate over the HashMap's key/value pairs, and build the string (which is what I'm using now, but I feel the conversions are excessive?).
I'm guessing there's others I'm not thinking of.
The main post I've looked into is Java: Getting the properties of a class to construct a string representation
My point is that I have several classes that I want to be able to serialize without having to specify something specific for each. That's why I'm thinking a function using reflection (#2 above) is the only way to handle this (if I have to do it manually).
If it helps, an example of what I mean is with, say, these two classes:
public class C1 {
private String C1prop1;
private String C1prop2;
private String C1prop3;
// Getters and setters for the 3 properties
}
public class C2 {
private String C2prop1;
private String C2prop2;
private String C2prop3;
// Getters and setters for the 3 properties
}
(no, the properties names and conventions are not what my actual app is using, it's just an example)
The results of serializing would be C1prop1=value&C1prop2=value&C1prop3=value and C2prop1=value&C2prop2=value&C2prop3=value, but there's only one place that defines how the serialization happens (already defined somewhere, or created manually by me).
So my idea is that I will have to end up using a form of the following (taken from the post I linked above):
public String toString() {
StringBuilder sb = new StringBuilder();
try {
Class c = Class.forName(this.getClass().getName());
Method m[] = c.getDeclaredMethods();
Object oo;
for (int i = 0; i < m.length; i++)
if (m[i].getName().startsWith("get")) {
oo = m[i].invoke(this, null);
sb.append(m[i].getName().substring(3) + ":"
+ String.valueOf(oo) + "\n");
}
} catch (Throwable e) {
System.err.println(e);
}
return sb.toString();
}
And modify it to accept an object, and change the format of the items appended to the StringBuilder. That works for me, I don't need help modifying this now.
So again, my main question is if there's something that already handles this (potentially simple) serialization instead of me having to (quickly) modify the function above, even if I have to specify how to deal with each property and value and how to combine each?
If it helps, the background of this is that I'm using a RestTemplate (Spring) to make a GET request to a different server, and I want to pass a specific object's properties/values in the URL. I understand I can use something like:
restTemplate.getForObject("URL?C1prop1={C1Prop1}&...", String.class, C1Object);
I believe the properties will be automatically mapped. But like I said, I don't want to have to make a different URL template and method for each object type. I'm hoping to have something like the following:
public String getRequest(String url, Object obj) {
String serializedUri = SERIALIZE_URI(obj);
String response = restTemplate.getForObject("URL?" + serializedUri, String.class);
return response;
}
where SERIALIZE_URI is where I'd handle it. And I could call it like getRequest("whatever", C1Object); and getRequest("whateverElse", C2Object);.
I think, solution number 4 is OK. It is simple to understand and clear.
I propose similar solution in which we can use #JsonAnySetter annotation. Please, see below example:
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonProgram {
public static void main(String[] args) throws Exception {
C1 c1 = new C1();
c1.setProp1("a");
c1.setProp3("c");
User user = new User();
user.setName("Tom");
user.setSurname("Irg");
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.convertValue(c1, UriFormat.class));
System.out.println(mapper.convertValue(user, UriFormat.class));
}
}
class UriFormat {
private StringBuilder builder = new StringBuilder();
#JsonAnySetter
public void addToUri(String name, Object property) {
if (builder.length() > 0) {
builder.append("&");
}
builder.append(name).append("=").append(property);
}
#Override
public String toString() {
return builder.toString();
}
}
Above program prints:
prop1=a&prop2=null&prop3=c
name=Tom&surname=Irg
And your getRequest method could look like this:
public String getRequest(String url, Object obj) {
String serializedUri = mapper.convertValue(obj, UriFormat.class).toString();
String response = restTemplate.getForObject(url + "?" + serializedUri, String.class);
return response;
}
Lets we have c1.
c1.setC1prop1("C1prop1");
c1.setC1prop2("C1prop2");
c1.setC1prop3("C1prop3");
Converts c1 into URI
UriComponentsBuilder.fromHttpUrl("http://test.com")
.queryParams(new ObjectMapper().convertValue(c1, LinkedMultiValueMap.class))
.build()
.toUri());
After we will have
http://test.com?c1prop1=C1prop1&c1prop2=C1prop2&c1prop3=C1prop3

Restlet with many #Get in my server side

So I am new with restlet. I am creating a Android application that can communicate with a GAE server (with objectify DB)
I Did this very good tutorial to learn:
http://www.tutos-android.com/webservice-rest-android-appengine-restlet-objectify
It's working very well but do very little.
Onely 2 methods:
public interface UserControllerInterface {
#Put
void create(User user);
#Get
Container getAllUsers();
}
For my application its more complicated so I add many more methods:
public interface UserControllerInterface {
#Put
public void createUser(ObagooUser user);
#Put
public void createMessage(ObagooUser user, String message);
#Put
public void updateMessage(ObagooMessage message);
#Get
public List<ObagooUser> getAllUser();
#Get
public ObagooUser getUserById(String id);
#Get
public List<ObagooMessage> getAllMessage();
#Get
public List<ObagooMessage> getAllMessageFromSender(ObagooUser sender);
#Get
public ObagooMessage getFreeMessage(ObagooUser user);
}
Each of these mothds working server side (I tested with Junit).
Now I am coding the android part and I am having problems.
When I do a simple call to getAllMessage() I get an error:
java.lang.IllegalArgumentException: id cannot be zero
at com.google.appengine.api.datastore.KeyFactory.createKey(KeyFactory.java:44)
at com.googlecode.objectify.ObjectifyFactory.typedKeyToRawKey(ObjectifyFactory.java:269)
at com.googlecode.objectify.impl.ObjectifyImpl.find(ObjectifyImpl.java:159)
at com.googlecode.objectify.impl.ObjectifyImpl.find(ObjectifyImpl.java:183)
at com.obagoo.dao.ObagooUserDAO.getUserById(ObagooUserDAO.java:43)
at com.obagoo.controller.ObagooController.getUserById(ObagooController.java:47)
It's going in the wrong method (getUserById).
I put a break point in my getAllMessage and it's going in, but it is also going in other methods.
If I test many times, sometimes it's calling, createUser or another random method.
Do you see what I am doind wrong?
Adding the getAllMessage code:
public List<ObagooMessage> getAllMessage() {
// logger.debug("Getting all Obagoo Messages");
List<ObagooMessage> msg = new ArrayList<ObagooMessage>();
Objectify ofy = ObjectifyService.begin();
Query<ObagooMessage> q = ofy.query(ObagooMessage.class);
for (ObagooMessage u : q) {
msg.add(u);
}
return msg;
}
In the examples that I've seen, its always shown that you should separate the controller/resource handling the URI for the list resource from the single item (id/name based) resource. So you would have something like:
router.attach("/users", UsersController.class);
router.attach("/users/{id}", UserController.class
router.attach("/messages", MessagesController.class);
Notice the plural naming on the first class: UsersController, and singular naming on the the second class: UserController. The first class would handle cases where no id was being provided, such as a get of all users. Also, note when the id is provided in the URI, it can be automatically mapped into an id field on the class. So the Get method has no parameters on the method call.
As for handling a subset, then for messages from a specific user, that could be handled with query parameters. For instance when calling via a URI with /messages?sender=id, the MessagesController.class would use the following in the method handling the Get:
Form queryParams = getRequest().getResourceRef().getQueryAsForm();
String id = queryParams.getFirstValue("sender");
Hope that helps. I'm no expert, so anyone feel free to correct me.
As error says: you are creating a key with zero Id.
My gues is that your ObagoMessage Id field is long? You should make it Long. Primitive long Id values are not autogenerated, while object type Long are. See the docs.

Does Restlet support parsing URLs into calling methods with parameters?

Take the following example.
I have a resource
public class HelloWorldResource extends ServerResource {
#Get
public String represent(String arg) {
return "hello, world (from the cloud!)" + arg;
}
}
That is mapped by
router.attach("/hi/{message}", HelloWorldResource.class);
Is it possible to configure the routing such that accessing /hi/somestuffhere will make restlet fill in the arg parameter in the represent method?
Try this:
String msg = (String) getRequest().getAttributes().get("message");
You can place this in an overriden doInit() method in order to let this happen automatically for all your requests to this resource.

Categories