Combining StepExecution context late-binding and property placeholder in Spring - java

I would like to access something like this "${#{stepExecution.stepName}.classificationSource}" for a property on a bean.
This is basically a lookup of "{stepname}.String" from a property file.
But #{stepExecution.stepName} is resolved only at beforeStep by Spring batch, whereas Spring attempts to load ${..} on bean loading itself, thereby causing errors. IS there any workaround for this?
UPDATE :
As OP suggested i moved from nesting of params. I modified the property file structure so as to set on "stepExecutionContext" by implementing "StepExecutionListener" and using the "beforeStep" method. By setting i mean setting a value for the key classificationSource on the executionContext, Thereby reducing the expression to "#{stepExecutionContext['classificationSource']}"
Upon debugging the setter method for this property field is invoked before the invocation of the "beforeStep" method, thereby not changing the field desirably. What am i missing here?
EDIT
My bad having the listener and bean as the same Class. Moved the listener and added in xml and its working fine.

Related

Spring boot cross-reference issue randomly occurs

I got a circular dependencies (cross-reference) issue when building a Spring boot project, and the dependencies trend like below:
Processor class autowired Criteria class via the constructor injection;
Criteria class autowired CacheManager via the constructor injection;
CahceManager class autowired the RuleSet class via the setter injection;
RuleSet class autowired the Processor again via the constructor injection.
The dependencies of some of the beans in the application context form a cycle:
app
┌─────┐
| XXXProcessor defined in file ...
↑ ↓
| XXXCriteria defined in file ...
↑ ↓
| XXXCacheManager
↑ ↓
| XXXRuleSet defined in file ...
└─────┘
While I can make an effort to remove the dependency of Processor from RuleSet class, I was wondering if there is a way of keeping the current references but still eliminating the cross-reference issue as presented here? I looked up this forum and someone suggested that the #Lazy annotation might help. I tried to apply it to either the Processor class or the RuleSet class (on either class level or method level), the issue didn't go away.
Another observation is that, the above quoted error didn't appear all the time - sometime the program proceeds just fine, it's that the error randomly occurs that bugged me. And why is that?
One way to solve it is to replace one instance with a Provider like this:
public Processor(Provider<Criteria> criteria) {
this.criteria = criteria;
}
Then when using it you need to get() it first.
Criteria c = this.criteria.get();
This means that Processor can be constructed before Criteria since the injected Provider will get the Criteria bean once it's ready.
This means that you cannot call get() in the constructor or you'll get a runtime error since that would still mean a circular construction dependency.
#Lazy just means that Spring should wait with initialising a bean until it is actually requested instead of eagerly creating it on startup (which is standard behaviour). This has zero impact on both circular dependencies and beans that are injected into other beans constructors. It is useful for beans that are very slow to initialize and must almost always be used from a Provider to actually defer initialisation.
You can replace constructor injection with field injection in one place. It shall break the cycle of circular objects instantiation.
It's hard to say why does this issue happen from time to time. Perhaps, there are some #Configuration classes that build different implementations of the same interface depending on config values. You should provide more details to deal with this problem.

To provide nicer logging when a Spring property is invalid

Using a application.properties file my Spring Boot app can use some property values in it. A way to make sure a mandatory value must present is to add an annotation #Value for the property. The problem with this is the app fails miserably if the property value is not there in the properties file.
I am after a nicer less horrible way to say printing out a log line about "Property A is missing" instead of a whole stack trace. Is there a way to do this while still using #Value to initialise the properties? For example, property A is mandatory, an error is logged before app exits; property B is missing but not mandatory, a warning is logged and app continues.
If you can identify all property, then you can write a method in Application class with #Postconstruct, and inside your method, you can manually validate and log them
#Autowired
private Environment environment;
#PostConstruct
private void validateProperties() {
environment.getProperty(key);
.....
......
}
Alternatively, you can write your custom EnvironmentPostProcessor, and iterate all properties and log whichever is null/empty.
As you're using spring-boot consider creating a #ConfigurationProperties class rather than using the #Value annotation.
By doing that you can do your validations using Bean Validation, also in the same class, you can implement the interface InitializingBean and add extra validations/log messages as you with.
Follow this link on Spring's official docs to read more about #ConfigurationProperties.

Spring 4 conditional - Accessing a resource

Doing my first steps with spring 4 I tried the #Conditional annotation following this article.
My problem -
I would like to get access to a classpath resource (basically a properties file) from method matches in class OnSystemPropertyCondition.
To do that currently I'm loading the required properties file from the matches method every time it is invoked (which means for every class annotated with the ConditionalOnSystemProperty annotation).
This is a bit ugly. I thought that an elegant solution would be to simply autowire my resource or some properties (using the #Value annotation) but this can't be done since this class gets instanciated before the beans.
Any suggestions than can help me avoid reload this resource again and again?
The single method of the annotation gets in its signature the input param ConditionContext context. You can obtain an Environment from the context by calling context.getEnvironment(). The environment gives access to all my resources (look at this to see how to get access to your resources via spring environment).

Spring MVC send properties via controller to a xml declared bean

I wanted to know if I can pass a property to a bean I declared on a xml configuration file (for example on the applicationContext.xml):
<bean id="captchaVerifierFilter" class="org.abc.filter.CaptchaVerifierFilter"
p:useProxy="false"
p:proxyPort=""
p:proxyHost=""
p:failureUrl="/abc/main/loginfailed"
p:captchaCaptureFilter-ref="captchaCaptureFilter"
/>
I want to use the captchaVerifierFilter bean to test if a captcha is valid or not. Then I can set the failureUrl property to url "add-record" and redirect to that jsp.
How can I send a property (like failureUrl for example) through a controller. Is this possible? What should I code on the controller if it's possible?
Any idea? Thank you very much!
I think you should define both the success and the failure url as properties in your configuration and then let the filter decide which way to go.
You can change the properties of the bean if you make it accessible (by making it public or with a setter) but that is probably not want you want since it changes the property for the single bean instance in the application context which is used by several threads concurrently.
Best regards
Hacim
By default the beans in the context are in singleton scope. So when you set the value for the property failureUrl in one controller, another controller will also see this new value when it gets the bean from the context.

Spring beans and changing bean parameter in application life cycle

I have a web application that is based on Spring. There is defined a bean that holds some class MyClass that is passed also with beans to MyEndpoint that extends AbstractMarshallingPayloadEndpoint.
MyClass has set some boolean parameter in beans to true.
If my application will change this parameter programically to false, does next request will have it also set to false or it will contains a default bean parameter - true ?
It depends on the scope of the bean (which will default to singleton, if you don't specify one).
If it is of singleton scope, there is one instance of that bean in the application context, and each time you ask for that bean, you get that single instance. If you change it in a request with this scope, then the change will be maintained.
If it is of prototype scope, a new instance is given to you (created with the same parameters) each time you ask the application context for it. If you change it in a request with this scope, then the change will be ignored when you get another instance of this object.
These are the two most commonly used (at least with my time in Spring). There are other scopes (request, session, globalsession), but you should read the documentation on them that Spring provides.
If you want this property to change dynamically according to your application business logic and not only to be reset on every new request (otherwise Request scope will do the magic) consider Factory Methods (especially Lookup Method Injection)

Categories

Resources