Access enum.valueof() from apache camel route - enums

I am comparatively newbie to apache camel. I am working on route called 'Upgrade' using Java DSL. I have java bean called 'Action' which has an enum,
public enum bundle{
AAA("Monthly AAA Bundle"),
BBB("Monthly BBB Bundle");
private String upbundle;
private bundle(String upBundle) {this.upbundle = upBundle;}
private getBundle() {return upbundle;}
}
From route I want to call 'valueOf()' on enum to get BundleName. I have enum value 'AAA' in exchange header. Using 'AAA' i want to retrieve enum value i.e. 'Monthly AAA Bundle' and store it in exchange header name 'destBundleName'
I used
.setHeader("destBundleName", simple(Action.bundle.valueOf(header("bm").toString()).getBundle()))
is given me runtime error "No enum constant Action.bundle.header{bm} at java.lang.Enum.valueOf
but if i use
.setHeader("destBundleName", simple(Action.bundle.valueOf("AAA")).getBundle())) it works fine.
It means in 1st e.g. header("bm").toString() is not replacing it with String.
I can write process() or bean method which calls enum valueof & from my route i can use that bean method but Is there any way to access enum valueOf() directly from route using value from camel header as a valueOf() param.
Thank you so much for help.

Related

Spring boot model class property validation

I am trying to map a json object to a Spring boot model class now the contract says for a property it have only a certain set of allowed values(not more than 3).
Example:
Suppose that json has field "name" and the contract says allowed values for field "name" are john,todd,phil
Anything other than john,todd,phil wont be accepted.
Is there any way to achive this constraint using any annotations
You can use following solutions
Solution 1:
Using #Pattern annotation with regex , if you want to use case insensitive use appropriate flags
#Pattern(regexp = "john|todd|phil", flags = Pattern.Flag.CASE_INSENSITIVE)
Solution 2:
By creating a enum class type with allowed values
public enum {
JOHN, TODD, PHIL
}
In your model class use #Enumerated(EnumType.STRING) on name filed

Deserialize nested Kotlin object in springMVC

I'm trying to deserialize a complex GET request into a structure of nested objects.
The GET requests looks like:
curl 'localhost:8080/?id=1&inner.id=1'
and the code should look like this:
class RootObj(val id: Int, inner: InnerObject)
class InnerObject(val id: Int)
#RestController
class SearchController {
#GetMapping(path = ["/"])
fun getRoot(rootObj: RootObj): String {
return "ok"
}
}
This doesn't work out of the box I guess because spring doesn't know how properly create this nested structure.
Parameter specified as non-null is null: [...] parameter inner","path":"/"}%
Is there a way to overcome this problem? Maybe providing a totally custom deserializer code?
As alternative solution, I guess I could flatten the object hierarchy but for doing so I must be able to map a query parameter like inner.id to a field named innerId
Spring can actually map the query params to the custom object directly, but you need to provide defaults to the params of the custom object constructor.
So you need to define your classes as below for it to work
class RootObj(val id: Int = 0, val inner: InnerObject = InnerObject(0))
class InnerObject(var id: Int = 0)
Do note that the id field of InnerObject would have to be declared as var for Spring to be able to map it. Then curl 'localhost:8080/?id=1&inner.id=1' would work fine.

How can I prevent a null RequestParam raising an exception?

I'm working in a Spring Boot environnement using Kotlin. I made a controller with a method annotated with #GetMapping. This method have some parameters of type #RequestParam declared as Double type. If I try to call my method without providing these parameters, my code raises the following exception:
java.lang.IllegalStateException: Optional double parameter 'latitude' is present but cannot be translated into a null value due to being declared as a primitive type.
I assume that the parameters have default value (probably 0.0), but Kotlin need an object which can be null, so the exception is raised.
All works fine if I provide the parameters, but I want my code working if no parameters are provided.
How can I avoid this exception?
Here's how my controller looks like:
#RestController
#RequestMapping("/api/stations")
class StationController {
#GetMapping
fun findAll(#RequestParam(value = "latitude", required = false) currentLatitude: Double,
#RequestParam(value = "longitude", required = false) currentLongitude: Double): ResponseEntity<List<Entity>> {
//Method body
}
Maybe the following part of the documentation regarding basic types will help you:
On the Java platform, numbers are physically stored as JVM primitive types, unless we need a nullable number reference (e.g. Int?) or generics are involved. In the latter cases numbers are boxed.
Your guess might be correct then. Try using Double? and it should be ok.

Passing json "data" array in Retrofit 2

I'm trying retrofit 2 for the first time and I have no idea how to tell it to get "Category" objects from an jsonarray named "data".
Method 1
If I do it like this it fails:
#GET("category")
Call<List<Category>> listCategories();
Method 2
But when I make a new model, called "Categories", which holds a List and is annotated with #SerializedName("data"), it works flawlessly.
#GET("category")
Call<Categories> listCategories();
My Question
Should I annotate something in the interface, like this
#GET("category")
#Annotation to look inside "data"
Call<List<Category>> listCategories();
Or should I annotate my "Category" model to tell Retrofit (or GSON)
that it lives inside the json array "data"?
JSON
{"data":[{"id":1,"name":"Fist Name","parent":0},{"id":2,"name":"Second Name","parent":1}]}
Method 2 Is correct and we use it when we dont want to use/define the json response object/arrays key names(field names). instead provide our own. Eg. In below code List object name is items but while Serialization and Deserialization it uses, what you have defined in #SerializedName annotation that is data.
public class Categories {
//solution 1
List<Category> data;//object name must match with the json response
//solution 2
#SerializedName("data")
List<Category> items;
}
Should I annotate something in the interface
No. There is no such annotation available and everything you can do is only in Response type class.

In Spring MVC 3, how do I bind an object to a query string when the query string parameters don't match up with the object fields?

A 3rd party is sending me part of the data to fill in my domain object via a query string. I need to partially fill in my domain object, and then have the user fill in the rest via a form. I don't have any control over the query string parameters coming in, so I can't change those, but I'd really like to be able to use Spring MVC's data binding abilities, rather than doing it by hand.
How can I do this?
To add some complication to this, some of the parameters will require extensive processing because they map to other objects (such as mapping to a user from just a name) that may not even exist yet and will need to be created. This aspect, I assume, can be handled using property editors. If I run into trouble with this, I will ask another question.
Once I have a partially filled domain object, passing it on to the edit view, etc. is no problem, but I don't know how to properly deal with the initial domain object population.
The only thing I have been able to come up with so far is to have an extra class that has it's properties named to match the inbound query parameters and a function to convert from this intermediary class to my domain class.
This seems like a lot of overhead though just to map between variable names.
Can you not just have the getter named differently from the setter, or have 2 getters and 2 setters if necessary?
private int spn;
// Standard getter/setter
public int getSpn() {
return spn;
}
public void setSpn(int spn) {
this.spn = spn;
}
// More descriptively named getter/setter
public int getShortParameterName() {
return spn;
}
public void setShortParameterName(int spn) {
this.spn = spn;
}
Maybe that is not standard bean convention, but surely would work?

Resources