Play framework: how to pass parameters extracted in the onRequest function - java

I overwrote the public Action onRequest(final Http.Request request, Method method) method to check that the mandatory http headers are passed in and valid, i.e.: I extract the apiKey (and other things) and make sure that these are valid (that there's data associated with the apiKey). Then I call return super.onRequest(request, method); and I end up in my controller where I once again have to extract the apiKey and get the associated data from the DB.
Is there a way to pass in the data to my controller's method (for instance: public static Result addUser() ).
Thank you.

I know this question is for Java, but I work with Play in Scala, and this question is more related to Play then it is to Java
In Scala I am able to extend WrappedRequest to make my own custom request type, that has instance variables I want to access in my controller:
// Scala code
case class MyRequest[A](request: Request[A]) extends WrappedRequest(request) {
// This is a public instance variable
val apiKey = request.headers.get("Authorization)
}
Then later on in my controller I can access the action object which now has the type of MyRequest:
// Scala code
def foobar(action: MyRequest[AnyContent]) = Action {
// Do something with the api key
val apiKey = action.apiKey
// Send back a response
Ok("foobar")
}
In Java it looks like you can do something similar using a Wrapped Context

Related

How can I pass a HashMap as parameters

I have a class API, where you set and get the info you need to later be used on a API call
I want to make it easier to the next person who's gonna use this.
So instead of doing this:
api.addURL("urltorequesttoken");
api.addHeader("client_id","sdfsfsdfsd")
.addHeader("client_secret","sdfsdfsfsfd")
.addHeader("grant_type","client_credentials")
.addHeader("scope","READ");
api.addBody("bodyToSend")
I want to do this:
String URL = "";
URL = "put your URL here";
So I pass the URL and other variables as a parameter to another method where I will be doing what I did in the first block of code,so they don't need to know about the API class and its methods, but I dont know how to handle the hashmap, how can I do that user friendly? and then pass that as a parameter, also, what type of parameters should the methods receiving this info have? (Map<String key, String value>) or (String key, String value)?
EDIT(ADD):
So there's a class that a DEV is going to create, let's call it CreateToken
, so that class currently has:
api.addURL("urltorequesttoken");
api.addHeader("client_id","sdfsfsdfsd")
.addHeader("client_secret","sdfsdfsfsfd")
.addHeader("grant_type","client_credentials")
.addHeader("scope","READ");
api.addBody("bodyToSend")
There's another class called BASE, where Im doing the core services, in order for this to be easier for the person when they create their class, I dont want to have that block of code on their class, but instead, on mine, so in their class all they have to do is set the URL, headers and body(for POST method), so instead of this:
api.addURL("urltorequesttoken");
they will do:
URL = "urltorequesttoken";
and there's a method on their class to send me this or for me to get it i,e.
fillAPICallInfo(URL, headers, body);
I will receive that on the BASE class, but I dont know how to handle the Map variables, don't know how to make it easy for the DEV so they just put the key and value, and how do I receive that on my class (as a Map or as Strings)?
So you simply can pass a Map<String, String> as parameter:
public void fillAPICallInfo(String url, Map<String, String> headers, String body) {
// Assuming there is an instance of class DEV named api available
api.addURL(url);
headers.forEach((h, v) -> api.addHeader(h, v));
api.addBody(body);
}

Angular: How to assign a List returned by Spring Model to Angular Object?

I have a requirement where am setting up a List of objects as model attribute in spring controller and I need it to assign to an object in angular .ts file.
Here is what I need to do. My java object:
public class Lab {
//some members of the class
}
This is how am adding it to Model:
public String getIndexPage(#RequestParam(value="val") List<Lab> labs, Model model){
model.addAttribute("val", labs);
return "index.html";
}
The corresponding object in Angular named inside lab.ts:
export class Lab {
// same variables as in java
}
And here is the component.ts file where I need to assign the val list:
export class VideoFormComponent implements OnInit {
selectedValues: Lab[] = new Array(4);
ngOnInit() {
this.selectedVideos = "${model.val}"; //assignment statement
}
But here is where am getting the error which says:
Type '"${model.val}"' is not assignable to type 'Lab[]'
What is the correct way to use that list inside the script file?
"${model.val}" is just a string in Typescript.
If model.val is an array of objects that are shaped like Lab[], you can do this.selectedVideos = <Lab[]>model.val.
If model.val is an array already typed as Lab[], you can simply say this.selectedVideos = model.val
I'm not sure what you're trying to do, but I'm assuming you're using Angular HttpClient or websocket or something to first get the data from a server endpoint to the client.
How are you providing the model data to the angular component? If your data comes from a Http request you should create a service that makes the request and then call it from your component and set the result in the selectedValues variable. Or if you are providing the data as an input to the component you should use the #Input decorator. In either case the data is provided externaly to the component. For what I read, you are trying to use a model object that has a val attribute, but you are not providing it anywhere.

Default/Constant values for POST/PUT arguments with Retrofit

Using the Retrofit REST Client library from Square, is there anyway of providing default/constant values for POST/PUT fields in a call.
I know about including constant query parameters by simply including them in the path, but this work for Body parameters.
I have an API that looks similar to:
POST /api/create
type=constanta&value={value}
POST /api/create
type=constantb&value={value}&otherValue={otherValue}
where the second variant requires an additional argument to be supplied. Rather than having a single java method that took all three arguments, I was hoping to be able to elide the constants from the method call, something like:
create(String value);
create(String value, String otherValue);
and have retrofit inject the type argument constant.
Given that adding #FormUrlEncoded can be added to modify how the body is encoded, if it's not natively supported by Retrofit, is there anyway of adding my own annotation and injecting such default values? ( It doesn't appear that RequestInterceptor allows one to modify the body.. ).
Maybe one option would be to send an object, which encapsulates all your values, instead of all string values separately? The object would implement your default values.
For example, you could create a class:
public class CreateObject {
private String type = "constant";
private String value;
private String otherValue;
public CreateObject(String value, String otherValue) {
this.value = value;
this.otherValue = otherValue;
}
}
Your class handles your constant. You could just set it to a default value "constant", like I did above, or set it on the fly in the constructor.
Now all you've to do is to create the object with the values and make the request with Retrofit. Instead of using the string values directly, just pass the object. Your interface could look like this:
public interface CreateService {
#POST("/api/create")
void create(#Body CreateObject create, Callback<CreateObject> cb);
}
The request implementation like this:
CreateObject create = new CreateObject("value", "otherValue");
createService.create(create, new Callback<CreateObject)() {…});
This should include all three of your values in the request body, if they are set. If a value is null, it won't be included in the request body. Based on your two examples above, you would now only need one interface method. Which values are sent is based on the createObject you pass on. For example, if you set otherValue as null, it won't be part of the request body.
My examples were modified from: https://futurestud.io/blog/retrofit-send-objects-in-request-body/
Is it possible for you to use Guava or Java 8 Optional as second argument in method? Then if that argument will be absent you can just ignore it

Consuming different input JSON format by same URL and same method in Spring RESTful service

I'm going to implement a RESTful webservice using Spring.
Let it be an ordinary PUT method, something like this:
#RequestMapping(method=RequestMethod.PUT, value="/foo")
public #ResponseBody void updateFoo(#RequestBody Foo foo) {
fooService.update(foo);
}
In such a case input JSON format (if it corresponds to Foo class) will be successfully converted to Foo instance with no extra efforts, or error will be issued in case of wrong format.
But I'd like to make the service able to consume two different types of formats using same method (e.g. PUT) and same URL (e.g. /foo).
So that it possibly looked like:
//PUT method #1
#RequestMapping(method=RequestMethod.PUT, value="/foo")
public #ResponseBody void updateFoo(#RequestBody Foo foo) {
fooService.update(foo);
}
//PUT method #2
#RequestMapping(method=RequestMethod.PUT, value="/foo")
public #ResponseBody void updateFoo(#RequestBody FooExtra fooExtra) {
fooService.update(fooExtra);
}
and Spring converter tried to convert input JSON not only in Foo but in FooExtra as well and invoked corresponding PUT method depending on input format.
In fact, I tried to implement it exactly as it described above but without success. Is it even possible? Maybe, I need some kind of "trick"?
What is the best (and the most proper) way to achieve such behavior? Of course, I could always make two different URLs but I'd like to know whether it is possible with the same one.
Your attempt didn't work simply because Spring tried to match your methods against the request, by looking at url and method type, which are in both cases the same. It does not work like overloading in Java; argument types do not differentiate your methods.
But there are good news. SpringMVC can also examine request headers and request parameters when trying to match your handler methods. Since what you want to pass is actually pure metadata -an alternative format type of the same information- it makes perfect sense to use a custom request header. It's very easy to add custom headers when using a rest api. See the following link for JAX-RS: Adding a custom header.
Now in your server side you should configure the handler methods as:
//PUT method #1
#RequestMapping(method=RequestMethod.PUT, value="/foo", headers="returnType=Foo")
public #ResponseBody Foo updateFoo(#RequestBody Foo foo) {
fooService.update(foo);
}
//PUT method #2
#RequestMapping(method=RequestMethod.PUT, value="/foo", headers="returnType=FooExtra")
public #ResponseBody FooExtra updateFoo(#RequestBody FooExtra fooExtra) {
fooService.update(fooExtra);
}
Note also that if you want to access a return value with #ResponseBody you have to return your object, otherwise make the methods void
For understanding it we should think how Spring works, it uses Dispatcher Servlet. I don't think that spring does "combine" work for different types of input.
So my answer will be: "trick" with two different urls ;)

Assigning/Passing value from Java function to JS/JQuery function

Lets say I have a Java function something like
public int getNumber(){
}
which returns some value based on it's logic. And I have a JS file something like
Tapestry.Validator.amountValidator = function(field, message) {
field.addValidator(function(value) {
if (value != null) {
// code here
}
}
});
};
Now I am asking myself is it possible in JS or JQuery to pass value from Java function to it's function(value) in JS and if so, how can it be achieved?
UPDATE: As suggested by abalos answer, Tap for myself has already done 3 out of 4 stages for it. I am providing a function that deals with server side and logic behind it.
#InjectComponent
private TextField amount;
#Inject
private FieldValidatorSource fieldValidatorSource;
public FieldValidator<?> getAmountValidator()
{
return fieldValidatorSource.createValidators(amount, "required,max=" + getBroj());
}
Now here validator is taken from a logic inside a function getBroj(), which is maximum number of what it takes. And this works like a charm on server side. Now I was thinking that what I don't have( using my logic ) is only Client side, and I can achieve it by updating current Validation class from Tapestry that will handle with this kind of request yet known to that class. And to do it I would need to call a js file with a function calling something like above in the example, but I am not quite sure how to pass value from getNumber() function to the JS function above.
You don't need Jersey or DWR or any other framework at all for invoking a method in Tapestry. You just need to ask your questions properly.
final private static String EVENT_NAME = "whateverEventNameYouWant";
#Inject
private ComponentResources resources;
#Inject
private JavaScriptSupport javaScriptSupport;
/** Method that will provide the value you want to pass to JS. */
#OnEvent(EVENT_NAME)
public JSONObject provideValue() {
JSONObject object = new JSONObject();
object.put("value", /* the value you want to pass to JS */);
// other values you may want to pass
return object;
}
void afterRender() {
// This creates an URL for the event you created. Requesting it will
// invoke any event handler methods for that event name.
Link link = resources.createEventLink(EVENT_NAME);
javaScriptSupport.addScript("var eventUrl = '%s';", link.); // the JavaScript variable name doesn't matter. You can choose any you want
}
Then, in your JavaScript, do an AJAX request using the URL in the eventUrl variable. I'll leave this part for you to figure out from the jQuery documentation. The received data is exactly the JSONObject or JSONArray you'll return in your event handler method.
I think you have some very heavy misconceptions into what types of languages Java and jQuery/Javascript are. First off, with the exception of node.js, jQuery/Javascript are used for client-side operations. Java is used for server-side operations. This means that you will need to pass a value from the server to the client.
Now, what you are asking for looks initially like it is trying to perform validation. This should not be completed only on the client-side. There are ways to get around client validation and it is best to leave information from the client in an "untrusted" state until it is validated on the server.
With all that said, to do what you are trying to do will require the use of some method for the client to communicate with the server. My favorite way to do this for simple operations is through a web service.
Here are steps to do what you require, but note that this is not the only way.
Create a web service with Jersey.
Pass the value to the web service via AJAX with either JSON or XML with a request that contains the value.
Perform your validation on the server-side with the information from the service.
Pass a response from the rest service back to the client-side AJAX call and use it for your JS/jQuery code.
Let me know if you have any questions.

Categories