I am trying to learn Scala using Spring framework. I have to implement conditional get logic in my code. I understand it could be done using etag or Last-Modified option.
Here is my piece of code:
var lastModifiedTime: Long = _;
#RequestMapping(value= Array("/users/{id}"),method=Array(RequestMethod.GET),headers = Array("Content-Type=application/json"))
#ResponseBody
def getmeth(request: User_details, web: WebRequest): User_details = {
if (web.checkNotModified(lastModifiedTime)) {
return null
} else {
lastModifiedTime = System.currentTimeMillis()
}
Could you please help me to fix this code?
Disclaimer: I don't know Spring Web.
But according to the documentation fist of all you should take action if request is modified so you should remove bang (!) from condition. Also lastModifiedTime should be computed from the outside of the getmeth method.
Notice that unlike in Java if statement is an expression and it returns value so you shouldn't use return statement.
As it was said in comment conditional code can be easy and safely done using Scala's Option. In Scala you should always avoid null, as it is hard to distinguish it from incorrect behavior of your code, and it is very easy to forget or don't know that it is required to write logic dealing with it - you must always read the javadoc (assuming it exists and it is up to date). When you use Option type compiler will force you to deal with "nullability".
def getmeth(request: User_details, web: WebRequest): Option[User_details] =
if (web.checkNotModified(lastModifiedTime)) {
None
} else {
val userDetails = yourLogic()
Some(userDetails)
}
Then you can perform an action when option is a Some instance. To do that you can use map method.
getmeth(req, web) map { userDetails =>
userDetails.getName
}
EDIT: #optimus Now when you gave wider scope I see that your method signature is forced by framework and yon can't wrap your value with Option. I think that your problem may be that you update lastModifiedTime on every request so it seems reasonable to me that checkNotModified is always false. I think that you should use that feature only on requests that not always update checkNotModified to current time. It becomes pointless otherwise.
Update lastModifiedTime once your resource has become outdated.
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = Array("/users/{user_id}"),method = Array(RequestMethod.GET))
def getUser(#PathVariable("user_id") user_id: String,
#Context req : Request ): Any = {
val u = hm.get(user_id).asInstanceOf[User]
val tag = u.hashCode().asInstanceOf[EntityTag]
if (req.getMethod().equals("GET")) {
val rb : Response.ResponseBuilder = req.evaluatePreconditions(tag);
if (rb != null)
{
rb
}
else
{
// val u = hm.get(user_id).asInstanceOf[User]
u
}
}
Related
I got this piece of code, I am learning from tutorial. I want to return an element by url which looks like clients/1 instead of clients?id=1. How can I achieve this? Also, can the code below be made easier way?
#GetMapping
public Client getClient(#RequestParam int id) {
Optional<Client> first = clientList.stream().filter(element -> element.getId() == id).findFirst();
return first.get();
}
You may want to use #PathVariable as follows:
#Controller
#RequestMapping("/clients")
public class MyController {
#GetMapping("/{id}")
public Client getClient(#PathVariable int id) {
return clientList.stream().filter(element -> element.getId() == id).findFirst().orElseThrow();
}
Please note, the Optional can be unpacked with orElseThrow method. This will throw a NoSuchElementException in case there is no element found for the id.
Other solution would be to use orElse(new Client(...)) to return a default value if nothing is found.
get() is not really recommended to be used. From the JavaDoc of the get() method:
API Note:
The preferred alternative to this method is orElseThrow().
Even though get() may also throw a NoSuchElementException, similar to orElseThrow, usually the consensus is that get should not be used without isPresent, or should not be used at all. There several other methods to unpack the Optional without forcing you write an if.
The whole idea of the Optional is to overcome this by forcing you to think about the case when there is no value inside.
I am trying to expose a rest endpoint with camel. It will show a json data which is inside some .json files stored in s3 bucket. Also, it will filter by a date range.
First, I got some s3 objects informations in my Camel routes. (I am using kotlin)
//expose the endpoint
from("jetty:http://0.0.0.0:8080/getObjects")
.routeId("list-objects-on-bucket")
.to("aws-s3://[bucket-name]?amazonS3Client=#s3Client&operation=listObjects")
.process(ListObjects())
.to("direct:filter-list-from-s3")
then, I filter the data. (Till here everything is alright)
from("direct:filter-list-from-s3")
.routeId("filter-list-from-s3")
.process(FilterObjects())
.to("log:info")
But in my FilterObject class I do not know how to download every files that matches (look the if statement) and pass it to the next route that will treat them
class SaoMateusFilterObjects : Processor {
override fun process(exchange: Exchange?) {
val start_date = exchange!!.getIn().getHeader("start_date") as String
val end_date = exchange.getIn().getHeader("end_date") as String
val formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy")
val start = LocalDate.parse(start_date).format(formatter)
val end = LocalDate.parse(end_date).format(formatter)
val objectsNames = exchange!!.getIn().body as LinkedList<String>
for (objectName in objectsNames) {
if(objectName.contains(start) && objectName.contains(end) && objectName.contains(".json")) {
exchange.getIn() to "aws-s3://[bucket-name]?amazonS3Client=#s3Client&operation=getObject&fileName=$objectName"
}
}
}
}
Some problems are:
1 - I want to read. By I think I can't use the from() method. Because it can be use just once. So, the to() method is used to read.
2 - exchange.getIn().to("[s3-uri]") maybe/must be converted in S3Object(). How??
Can Someone help me with this?
Thank you
Instead of .to route, use .bean() and use the s3.getObject method to get the S3Object.
always Prefer using .bean() over .processor().
offical_s3_java_object operation sample.
How to force URIBuilder.path(...) to encode parameters like "%AD"?
The methods path, replacePath and segment of URIBuilder do not always encode parameters with percentage, correctly.
When a parameter contains the character "%" followed by two characters that together form an URL-encoded character, the "%" is not encoded as "%25".
For example
URI uri = UriBuilder.fromUri("https://dummy.com").queryParam("param", "%AD");
String test = uri.build().toString();
"test" is "https://dummy.com?param=%AD"
But it should be "https://dummy.com?param=%25AD" (with the character "%" encoded as "%25")
The method UriBuilderImpl.queryParam(...) behaves like this when the two characters following the "%" are hexadecimal. I.e, the method "com.sun.jersey.api.uri.UriComponent.isHexCharacter(char)" returns true for the characters following the "%".
I think the behavior of UriBuilderImpl is correct because I guess it tries to not encode parameters that already are encoded. But in my scenario, I will never try to create URLs with parameters that already encoded.
What should I do?
My Web application uses Jersey and in many places I build URIs using the class UriBuilder or invoke the method getBaseUriBuilder of UriInfo objects.
I can replace "%" with "%25", every time I invoke the methods queryParam, replaceQueryParam or segment. But I am looking for a less cumbersome solution.
How can I make Jersey to return my own implementation of UriBuilder?
I thought of creating a class that extends UriBuilderImpl that overrides these methods and that perform this replacing before invoking super.queryParam(...) or whatever.
Is there any way of making Jersey to return my own UriBuilder instead of UriBuilderImpl, when invoking UriBuilder.fromURL(...), UriInfo.getBaseUriBuilder(...), etc?
Looking at the method RuntimeDelegate, I thought of extending RuntimeDelegateImpl. My implementation would override the method createUriBuilder(...), which would return my own UriBuilder, instead of UriBuilderImpl.
Then, I would add the file META-INF/services/javax.ws.rs.ext.RuntimeDelegate and in it, a the full class name of my RuntimeDelegateImpl.
The problem is that the jersey-bundle.jar already contains a META-INF/services/javax.ws.rs.ext.RuntimeDelegate that points to com.sun.jersey.server.impl.provider.RuntimeDelegateImpl, so the container loads that file instead of my javax.ws.rs.ext.RuntimeDelegate. Therefore, it does not load my RuntimeDelegateimplementation.
Is it possible to provide my own implementation of RuntimeDelegate?
Should I take a different approach?
UriBuilder
This is possible with help of UriComponent from Jersey or URLEncoder directly from Java:
UriBuilder.fromUri("https://dummy.com")
.queryParam("param",
UriComponent.encode("%AD",
UriComponent.Type.QUERY_PARAM_SPACE_ENCODED))
.build();
Which result in:
https://dummy.com/?param=%25AD
Or:
UriBuilder.fromUri("https://dummy.com")
.queryParam("param", URLEncoder.encode("%AD", "UTF-8"))
.build()
Will result in:
https://dummy.com/?param=%25AD
For a more complex examples (i.e. encoding JSON in query param) this approach is also possible. Let's assume you have a JSON like {"Entity":{"foo":"foo","bar":"bar"}}. When encoded using UriComponent the result for query param would look like:
https://dummy.com/?param=%7B%22Entity%22:%7B%22foo%22:%22foo%22,%22bar%22:%22bar%22%7D%7D
JSON like this could be even injected via #QueryParam into resource field / method param (see JSON in Query Params or How to Inject Custom Java Types via JAX-RS Parameter Annotations).
Which Jersey version do you use? In the tags you mention Jersey 2 but in the RuntimeDelegate section you're using Jersey 1 stuff.
See if the following examples help. The thread linked below has an extensive discussion on the available functions and their differing outputs.
The following:
UriBuilder.fromUri("http://localhost:8080").queryParam("name", "{value}").build("%20");
UriBuilder.fromUri("http://localhost:8080").queryParam("name", "{value}").buildFromEncoded("%20");
UriBuilder.fromUri("http://localhost:8080").replaceQuery("name={value}).build("%20");
UriBuilder.fromUri("http://localhost:8080").replaceQuery("name={value}).buildFromEncoded("%20");
Will output:
http://localhost:8080?name=%2520
http://localhost:8080?name=%20
http://localhost:8080?name=%2520
http://localhost:8080?name=%20
via http://comments.gmane.org/gmane.comp.java.jsr311.user/71
Also, based on the Class UriBuilder documentation, the following example shows how to obtain what you're after.
URI templates are allowed in most components of a URI but their value
is restricted to a particular component. E.g.
UriBuilder.fromPath("{arg1}").build("foo#bar");
would result in encoding of the '#' such that the resulting URI is
"foo%23bar". To create a URI "foo#bar" use
UriBuilder.fromPath("{arg1}").fragment("{arg2}").build("foo", "bar")
instead. URI template names and delimiters are never encoded but their
values are encoded when a URI is built. Template parameter regular
expressions are ignored when building a URI, i.e. no validation is
performed.
It is possible to overwrite the default behavior in jersey manually at start up e.g. with a static helper that calls RuntimeDelegate.setInstance(yourRuntimeDelegateImpl).
So if you want to have an UriBuilder that encodes percents even if they look like they are part of an already encoded sequence, this would look like:
[...]
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.ext.RuntimeDelegate;
import com.sun.jersey.api.uri.UriBuilderImpl;
import com.sun.ws.rs.ext.RuntimeDelegateImpl;
// or for jersey2:
// import org.glassfish.jersey.uri.internal.JerseyUriBuilder;
// import org.glassfish.jersey.internal.RuntimeDelegateImpl;
public class SomeBaseClass {
[...]
// this is the lengthier custom implementation of UriBuilder
// replace this with your own according to your needs
public static class AlwaysPercentEncodingUriBuilder extends UriBuilderImpl {
#Override
public UriBuilder queryParam(String name, Object... values) {
Object[] encValues = new Object[values.length];
for (int i=0; i<values.length; i++) {
String value = values[i].toString(); // TODO: better null check here, like in base class
encValues[i] = percentEncode(value);
}
return super.queryParam(name, encValues);
}
private String percentEncode(String value) {
StringBuilder sb = null;
for (int i=0; i < value.length(); i++) {
char c = value.charAt(i);
// if this condition is is true, the base class will not encode the percent
if (c == '%'
&& i + 2 < value.length()
&& isHexCharacter(value.charAt(i + 1))
&& isHexCharacter(value.charAt(i + 2))) {
if (sb == null) {
sb = new StringBuilder(value.substring(0, i));
}
sb.append("%25");
} else {
if (sb != null) sb.append(c);
}
}
return (sb != null) ? sb.toString() : value;
}
// in jersey2 one can call public UriComponent.isHexCharacter
// but in jersey1 we need to provide this on our own
private static boolean isHexCharacter(char c) {
return ('0' <= c && c <= '9')
|| ('A' <=c && c <= 'F')
|| ('a' <=c && c <= 'f');
}
}
// here starts the code to hook up the implementation
public static class AlwaysPercentEncodingRuntimeDelegateImpl extends RuntimeDelegateImpl {
#Override
public UriBuilder createUriBuilder() {
return new AlwaysPercentEncodingUriBuilder();
}
}
static {
RuntimeDelegate myDelegate = new AlwaysPercentEncodingRuntimeDelegateImpl();
RuntimeDelegate.setInstance(myDelegate);
}
}
Caveat: Of course that way it is not very configurable, and if you do that in some library code that might be reused by others, this might cause some irritation.
For example I had the same problem as the OP when writing a rest client in a Confluence plugin, and ended up with the "manual encode every parameter" solution instead, as the plugins are loaded via OSGi and thus are simply not able to touch the RuntimeDelegateImpl (getting java.lang.ClassNotFoundException: com.sun.ws.rs.ext.RuntimeDelegateImpl at runtime instead).
(And just for the record, in jersey2 this looks very similar; especially the code to hook the custom RuntimeDelegateImpl is the same.)
We built a large insurance policy and claim management system using Grails and Groovy. Performance problems are slowing down the site because all 'READS' fetch from the database, which is not necessary since most data is static. We want to introduce a simple key/value cache in the Grails layer, but we don't want to litter the existing code with cache.get() and cache.set() code, we want to use aspects instead.
Here is a sample from our main controller....
InsuranceMainController {
def customer {
//handles all URI mappings for /customer/customerId
}
def policy {
//handles all URI mappings for /policy/policyId,
}
def claim {
//handles all URL mappings for /claim/claimId
}
As far as the cache goes, assume for the moment it's a simple Map named "cache" that's available as a globally-scoped object, and objects in the cache are keyed by request URI...
cache.put("/customer/99876", customerObject)
cache.put("/policy/99-33-ARYT", policyObject)
Going back to the controller, if we just litter the code with cache.get()/set(), which is what we want to avoid using Spring AOP, we'll end up with messy code. We want to achieve the following functionality with apsects, or with just a simpler and cleaner implementation...
InsuranceMainController {
def customer {
Object customer = cache.get(request.getRequestURI())
if ( customer != null)
//render response with customer object
}else
//get the customer from the database, then add to cache
CustomerPersistenceManager customerPM = ...
customer = customerPM.getCustomer(customerId)
cache.put(request.getRequestURI(), customer)
}
}
We need examples that show how we can achieve the above functionality using Spring AOP or something simpler in Grails while avoiding the littering of the code with cache.get()/set(). Suggestions to refactor the existing controller are welcome if it's required to get AOP working properly.
Thanks in advance
Rather than using AOP, you could adapt Mr Paul Woods' controller simplification pattern to move the cache handling out to a single method?
Something like this might work:
class InsuranceMainController {
def customer = {
Object customer = withCachedRef( 'customerId' ) { customerId ->
CustomerPersistenceManager customerPM = ...
customerPM.getCustomer(customerId)
}
}
def policy = {
//handles all URI mappings for /policy/policyId,
Object policy = withCachedRef( 'policyId' ) { policyId ->
PolicyPersistenceManager policyPM = ...
policyPM.getPolicy(policyId)
}
}
// ...
private def withCachedRef( String id, Closure c ) {
Object ret = cache.get( request.requestURI )
if( !ret ) {
ret = c.call( params[ id ] )
cache.put( request.requestURI, ret )
}
ret
}
}
However, I haven't tested it at all :-( Just a suggestion of an alternative to AOP
EDIT: Please let me be clear, I'm asking how to do this in Grails using Spring Dependency Injection, and NOT Grails' metaclass functionality or new().
I have a grails service that is for analyzing log files. Inside the service I use the current time for lots of things. For unit testing I have several example log files that I parse with this service. These have times in them obviously.
I want my service, DURING UNIT TESTING to think that the current time is no more than a few hours after the last logging statement in my example log files.
So, I'm willing to this:
class MyService {
def currentDate = { -> new Date() }
def doSomeStuff() {
// need to know when is "right now"
Date now = currentDate()
}
}
So, what I want to be able to do is have currentDate injected or set to be some other HARDCODED time, like
currentDate = { -> new Date(1308619647140) }
Is there not a way to do this with some mockWhatever method inside my unit test? This kind of stuff was super easy with Google Guice, but I have no idea how to do it in Spring.
It's pretty frustrating that when I Google "grails dependency injection" all I find are examples of
class SomeController {
// wow look how amazing this is, it's injected automatically!!
// isn't spring incredible OMG!
def myService
}
It feels like all that's showing me is that I don't have to type new ...()
Where do I tell it that when environment equals test, then do this:
currentDate = { -> new Date(1308619647140) }
Am I just stuck setting this property manually in my test??
I would prefer not to have to create a "timeService" because this seems silly considering I just want 1 tiny change.
Groovy is a dynamic language, and as such it allows you to do almost what you're asking for:
class MyServiceTests extends GrailsUnitTestCase {
def testDoSomeStuff() {
def service = new MyService()
service.currentDate = { -> new Date(1308619647140) }
// assert something on service.doSomeStuff()
}
}
Keep in mind this only modifies the service instance, not the class. If you need to modify the class you'll need to work with the metaClass. Take a look at this post by mrhaki.
Another option would be to make the current date a parameter to doSomeStuff(). That way you wouldn't need to modify your service instance.
Thanks for the help guys. The best solution I could come up with for using Spring DI in this case was to do the following in
resources.groovy
These are the two solutions I found:
1: If I want the timeNowService to be swapped for testing purposes everywhere:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
timeNowService(TimeNowMockService)
} else {
println ">>> not test env"
timeNowService(TimeNowService)
}
}
2: I could do this if I only want this change to apply to this particular service:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
time1(TimeNowMockService)
} else {
println ">>> not test env"
time1(TimeNowService)
}
myService(MyService) {
diTest = 'hello 2'
timeNowService = ref('time1')
}
}
In either case I would use the service by calling
timeNowService.now().
The one strange, and very frustrating thing to me was that I could not do this:
import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
if (GrailsUtil.environment == 'test') {
println ">>> test env"
myService(MyService) {
timeNow = { -> new Date(1308486447140) }
}
} else {
println ">>> not test env"
myService(MyService) {
timeNow = { -> new Date() }
}
}
}
In fact, when I tried that I also had a dummy value in there, like dummy = 'hello 2' and then a default value of dummy = 'hello' in the myService class itself. And when I did this 3rd example with the dummy value set in there as well, it silently failed to set, apparently b/c timeNow blew something up in private.
I would be interested to know if anyone could explain why this fails.
Thanks for the help guys and sorry to be impatient...
Since Groovy is dynamic, you could just take away your currentDate() method from your service and replace it by one that suits your need. You can do this at runtime during the setup of your test.
Prior to having an instance of MyService instantiated, have the following code executed:
MyService.metaClass.currentDate << {-> new Date(1308619647140) }
This way, you can have a consistent behavior across all your tests.
However, if you prefer, you can override the instance method by a closure that does the same trick.
Let me know how it goes.
Vincent Giguère