Wednesday 21 October 2020

Customer operation unique id for springfox swagger lib

 when using swagger, each operation can have a id, by default this id is nickname of the annotation, for instance, 

@ApiOperation(value = "create a new user", nickname = "oper_code_create_new_user")

The oper_code_create_new_user will be used as unique id (not sure why the lib use nickname as a unique id but it does). How if you do not add this annotation on the method, for instance, you may have a parent Controller class, and the sub-Controller class just reuse the method without override it. in this case, the unique id will be oper_code_create_new_user_1 by default (as implementated in CachingOperationNameGenerator.java in springfox-spring-web library)

if you want to customize the unique id in the sub-class, for instance, I want to add the sub-class name or the value defined in controller lever tag name which is in @Api annotation, as the suffix,  you can reference below code sneppet.

@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000)
public class OperationCustomizeUniqueIdReader implements OperationBuilderPlugin {

@Override
public void apply(OperationContext context) {
Optional<ApiOperation> apiOperation = context.findAnnotation(ApiOperation.class);

if (apiOperation.isPresent()) {
Optional<Api> apiOptional = context.findControllerAnnotation(Api.class);
if (apiOptional.isPresent()) {
String tagName = apiOptional.get().tags()[0];
ApiOperation operation = apiOperation.get();
String nickname = operation.nickname();

if (StringUtils.isNotEmpty(nickname) && StringUtils.isNotEmpty(tagName)) {
if (nickname.equalsIgnoreCase("oper_code_create_new_user") ) {
context.operationBuilder().uniqueId(nickname + "_" + tagName);
context.operationBuilder().codegenMethodNameStem(nickname + "_" + tagName);
}
}
}
}
}
@Override
public boolean supports(DocumentationType documentationType) {
return SwaggerPluginSupport.pluginDoesApply(documentationType);
}
}

if you have a sub class with @Api(tags = {"aSubResource"}), then you will get a unique name
for this method "oper_code_create_new_user_aSubResource"

Tuesday 6 October 2020

Passing parameters in Job and Step level in Spring Batch


1. Job level

Besides passing parameters when building a job, using Job Listener to pass extra job level parameters which can be used through the job running. Specifically, create a class who implements JobExecutionListener, override below method: 

@Override
public void beforeJob(JobExecution jobExecution)

In the method, add more parameters into job context as below:

ExecutionContext jobExecutionContext = jobExecution.getExecutionContext();
jobExecutionContext.put(someKey, someValue);

In Job's steps, using below code to introduce the parameter:

@Value("#{jobExecutionContext[someKey]}")
private SomeCalss someClassInstance; // the value will be someValue

2. Step level

How to pass parameters between Steps within a job?

It is the same as Job level, the Step should implement a Listener StepExecutionListener.

Say if you want to passing a parameter from step1 to step2. Step 1 should implements the above Listener, in afterStep method, add the parameter into execution context:

@Override
public ExitStatus afterStep(StepExecution stepExecution) {
// put a number into job execution context for future use
stepExecution.getJobExecution().getExecutionContext().putLong("aNumber", aNumber);
return null;
}

Step 2 also implements the Listener but in before step method to get the parameter out.

@Override
public void beforeStep(StepExecution stepExecution) {
aNumber = stepExecution.getJobExecution().getExecutionContext().getLong("aNumber");
}

Via this way you can passing parameters from one step to another.