Spring Batch Passing list of values as a parameter - spring

I want to pass list of id's as one of parameter to Spring batch. Is this possible to achieve?
Thanks in advance.

What you are trying to do is not possible.
From the JobParameter doc:
Domain representation of a parameter to a batch job. Only the
following types can be parameters: String, Long, Date, and Double. The
identifying flag is used to indicate if the parameter is to be used as
part of the identification of a job instance.
You might be tempted write your list of of id's to a comma delimited string and pass that as a single parameter but beware that when stored in the DB it has a length of at most 250 bytes. You'll either have to increase that limit or use another way.
Perhaps you can explain what why you need to pass that list of ids.

If you want to pass the list from ItemReader, then you have to get JobParameters first (you have to declare your reader to be step scoped for that, see this thread also).
You will have to put your list as a parameter to the JobParameters. As JobParameters is immutable, you will have to create a new object then
List yourList = ....
JobParameters jp = (JobParameters) fac.getBean("params");
Map map=params.getParameters();
map.put("yourList", list);
params=new JobParameters(map);
launcher.run(job, params);

You cannot use the List<T> concept itself in spring-batch, but I think you can implement your intentions(listOf(a, b, c, d..)) in the following way.
The job parameter itself receives a comma-separated string of items.
#Nonnull
private List<String> someList = Collections.emptyList();
#Value("#{jobParameters['someList']}")
public void setTableNames(#Nullable final String someList) {
if (StringUtils.isNotBlank(tableNames)) {
this.someList = Arrays.stream(StringUtils.split(someList, ","))
.map(String::trim)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toList());
}
}
Hope it was helpful for using list-type parameters in spring-batch!
Thanks.

Related

Using a Map<String, String[]> as #RequestParam in Spring with csv notation

Since one of my endpoints is getting more and more parameters i would like to convert noting down every parameter on its own into using a map. The parameters themselves consist of a two element array of values.
As an example:
Call: getstuff?param1=value1,gt&param2=value2,eq
Current Method: getStuff(#RequestParam String[] param1, #RequestParam String[] param2)
What i want: getStuff(#RequestParam Map<String, String[]> params)
If i do this, the String[] will only ever contain one String, and not be split on the comma into two values.
How can i achieve that it works the same as with the explicit parameters, preferrably without parsing things myself?

Spring AOP get method parameter value based on parameter name

Is it possible to get the method parameter value based on parameter name in Spring AOP.
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = signature.getMethod();
method.getParameters().getName()
// possible to get the paramater names
This approach will get parameter names, not value.
proceedingJoinPoint.getArgs()
will return values not names
Then is it possible to get the value based on a parameter name?
As I searched everywhere does not exist a function that gives parameter value by name and I wrote a simple method that makes this work.
public Object getParameterByName(ProceedingJoinPoint proceedingJoinPoint, String parameterName) {
MethodSignature methodSig = (MethodSignature) proceedingJoinPoint.getSignature();
Object[] args = proceedingJoinPoint.getArgs();
String[] parametersName = methodSig.getParameterNames();
int idx = Arrays.asList(parametersName).indexOf(parameterName);
if(args.length > idx) { // parameter exist
return args[idx];
} // otherwise your parameter does not exist by given name
return null;
}
I searched for the same thing when I had to use AOP for logging function arguments and their values but it seems there is no direct way to get value based on argument name.
What I noticed however us that value returned by method.getParameters().getName() and proceedingJoinPoint.getArgs() was always in sync., i.e., for function
public void foo(String a, String b)
called as
foo("hello", "world");
method.getParameters().getName() returned ["a", "b"] and proceedingJoinPoint.getArgs() returned ["hello", "world"], in order. So you can iterate over the array by index and for each index i, the i'th argument name would correspond to i'th argument value.
I couldn't find a supporting documentation for this behavior but hey, this code has been running on production servers for about an year it never has produced incorrect result. Though I'd be glad if someone can link to a documentation of this behavior. You may even dig into reflectiion's code to verify this behavior.

Factoring out a duplicated java 8 expression

I find myself duplicating over and over the same java 8 expression:
In one method, I have:
List<Message> latestMessages = new ArrayList<>();
...
return latestMessages.stream().map(messageMapper::asMessageDto).collect(toList());
Then in another method of the same class, I have:
List<Message> messagesBetweenTwoUserAccounts = ...;
return messagesBetweenTwoUserAccounts.stream().map(messageMapper::asMessageDto).collect(toList());
The return type of both methods is: List<MessageDto>
I basically convert from a List<Message> to a List<MessageDto>.
Notice the duplicated expression:
stream().map(messageMapper::asMessageDto).collect(toList());
What would be the best way to factor out the above expression using java 8 constructs?
If you don't want to repeat the latestMessages.stream().map(messageMapper::asMessageDto).collect(toList()); multiple times, write a method that contains it :
public static List<MessageDto> transformMessages (List<Message> messages) {
return messages.stream().map(messageMapper::asMessageDto).collect(toList());
}
Now you can call it from multiple places without repeating that Stream pipeline code.
I don't know if that method should be static or not. That depends on where you are calling it from, and where messageMapper comes from (as Holger commented). You can add messageMapper as an argument if different invocations of the method require different mappers.

Accessing public static final field using JoSQL

I've been using JoSQL for quite a few months now and today I came across a problem I am not sure how to solve. I probably could solve it by binding variables/placeholders, but I'd like to include the fields in the query.
SELECT * FROM ...MyObject WHERE getType != com.mypackage.myclass.TYPE_A
This is the query that I have. TYPE_A is a public static final int attribute in "myclass" class. Accessing methods (such as getType) is easy, because getType is expected to be a method from MyObject - just that I do not write round brackets after it (this is how JoSQL works as far as I know).
Does anyone happen to have an idea how to access a public static final field?
JoSQL uses gentlyweb-utils; it seems to be some sort of Accessor/Getter/Setter framework. I'd love to access that attribute without having to bind variables, but I haven't been able to do so.
Thanks for your help in advance! I really appreciate it.
I think I have figured something out. First: it seems not possible to access the static variables for whatever reason. I've used the following approach to solve my issue:
create a method, which picks up a given JoSQL-statement
mark the constants, which you want to replace, by say "{?FULL_PACKAGE_AND$CONSTANT}"
use reflections to determine the column as well as the column (and value) from the field
iteratively replace the statement until no "{?"-values are available
Example:
JoSQL-statement looks like this:
(isWeapon = TRUE AND getItem.getType2 = {?com.l2jserver.gameserver.model.items.L2Item$TYPE2_WEAPON})
Method using the query-object:
final Query query = DataLayer.createJoSqlQuery(joSql);
Method (pre)processing the JoSQL-statement:
final Query query = new Query();
int variableColumn = 0;
while (joSql.indexOf("{?") > -1) {
variableColumn++;
final int startIndex = joSql.indexOf("{?");
final int endIndex = joSql.indexOf("}", startIndex);
final String value = joSql.substring(startIndex + 2, endIndex);
try {
final Object variableValue = Class.forName(value.split("\\$")[0]).getField(value.split("\\$")[1]).get(null);
query.setVariable(variableColumn, variableValue);
joSql = joSql.replace("{?" + value + "}", "?");
}
catch (...) {
e.printStackTrace();
}
}
query.parse(joSql);
return query;
The JoSQL-statement preprocessing method bascially iterates through a given JoSQL-statement and sees whether it contains the string "{?". If it does, it does some copy and paste (note the dollar-symbol right in front of the constant name).
Finally it creates the objects and sets them using something similar to prepared statements "setObject"-method. In the end it just replaces the values within the JoSQL-statement with question marks ("?") and sets a corresponding object in the newly created Query-object, which is later used to retrieve information.

Map Support in Shell Scripting

I am new in Shell Scripting, however i am friendly with Java Maps. I Just wanted to know that how can i use Map facility in Shell Scripting. Below is the facility i need to use in shell-
HashMap<String, ArrayList<String>> users = new HashMap<String, ArrayList<String>>();
String username = "test_user1";
String address = "test_user1_address";
String emailId = "test_user1_emailId";
ArrayList<String> values = new ArrayList<String>();
values.add(address);
values.add(emailId);
users.put(username, values);
String anotherUser = "test_user2";
if (users.containsKey(anotherUser)) {
System.out.println("Do some stuff here");
}
In short, i want to use a Map, which has String as key, either Vector or ArrayList as value (otherwise i have live with Arrays instead of ArrayList and manually take care of indexes) , put method to insert and one more method to check the presence of the key in the existing Map.
The above code is a sample code.
Thank you in advance.
bash does not support nested structures like this. Either use separate variables for each array, or use something more capable such as Python.

Resources