Passing multiple #Value into a #Bean in a java class - java

I am trying to write a Spring Batch job that has two steps in it. They are both the same step but with different file locations. As such I need to pass multiple strings into the job bean to let the step know where to send the different files. However, it I try to pass the Resource values, I get a NoSuchBeanDefinitionException. The answers I found to this is that I need to add a #Value to the bean to tell it that the beans needs to a parameter to work.
But that is for only one value.
Is there a way to pass multiple #Values to a bean using java configuration? Below is the code I am using.
#Value("#{'${batch.outputFile}'}")
Resource outputFilePath;
#Value("#{'${batch.outputFileTrg}'}")
Resource outputFilePathTrg;
#Bean
public Step toServerStep(Resource outputFile) {
return stepBuilderFactory.get("toServerStep")
.chunk(1)
.reader(xmlFileItemReader())
.writer((ItemWriter<? super Object>) flatFileItemWriter(outputFile))
.build();
}
#Bean
public Job fileToServerJob(JobBuilderFactory jobBuilderFactory){
return jobBuilderFactory.get("fileToServerJob")
.start(toServerStep(outputFilePath1))
.next(toServerStep(outputFilePath2))
.build();
}

You can pass a delimited String as the property and break it apart into a list for your Value object.
#Value("#{'${batch.outputFiles}'.split(',')}")
private List<String> outputFilePaths;
With your application.property with the following
batch.outputFiles=/tmp/a,/tmp/b,/tmp/c
You can then use these path strings to grab the appropriate Resource to be used by your writer.

You are putting in a string, but shouldn't you put in a Rescource? Got one not so nice example that once worked for me here. Maby it can help you.

Related

Spring configure application.properties for placeholder in multitenant environment

I have a multi tenant environment so I need to change some path from application.properties in runtime to use the folder of specific tenant.
For example in my application properties:
image.avatars=C:/Users/Public/Pictures/Sample Pictures/${tenant}/Avatars/
in my class I use
#Autowired
private Environment env;
private static final String DIRECTORY_USER_IMAGE = "image.avatars";
.....Method
env.getRequiredProperty(DIRECTORY_USER_IMAGE)
I read about env.resolveRequiredPlaceholders but I don't understand how it can be used in my case since it has only one parameter like so env.resolveRequiredPlaceholders(TenantContext.getCurrentTenant()).
Is there a simple way to change the placeholder without manipulate String(with replace)?
I thought that env.resolveRequiredPlaceholders required the name of properties and the varargs of placeholder but it is different.
Thanks
You can use String.format().
Just use %s in properties
image.avatars=C:/Users/Public/Pictures/Sample Pictures/%s/Avatars/
And the in the code
String.format(imageavatars, tenant)
This might be not exactly what you want (because I struggle to understand your scenario), but what about putting
image.avatars=C:/Users/Public/Pictures/Sample Pictures/${tenant}/Avatars/
in your application.properties, and using
#Value("${image.avatars}")
private String DIRECTORY_USER_IMAGE;
in your bean/service and running the app with a command line argument like
--tenant="FooBar"
This would give DIRECTORY_USER_IMAGE the value C:/Users/Public/Pictures/Sample Pictures/FooBar/Avatars/ and you could change the CLI argument according to your needs. But be aware that DIRECTORY_USER_IMAGE is not static final anymore.
I hope I got your requirements right.

How to Mock the Property File in Junit

I am creating a Unit test case using Junit . Now My application is Maven Based with many profile Also I am using the Values from configuration file (Property File ) which Varies from one profile to other. I want that Unit Test run will have specified properties only not the profile one when it is running the test cases.
These can be done in 2 ways
1) Either i Mock the Property File for Unit Test .( which i dont know How) .
2) Or during run time i change the property file parameter values.(Again difficult to answer) . Any help will be appreciated .
One option: use dependency injection in order to acquire a java.util.Properties object for example.
Meaning: your production code simply holds a Properties object; like:
class Foo {
private final Properties properties;
public Foo(Properties) {
this.properties = properties;
At runtime, when the class that creates Foo objects reads property files from disk, turns them into a Properties object and gives it to the Foo constructor.
In your unit test, your test code creates a Properties object and adds whatever values you require upon creating a Foo object.
The less elegant detour: make sure that your production code reads its properties from a location that gets defined at runtime. That would allow you to create custom property files in some temp directory, and then you instruct your code under test to work with those files.
Did not got your question exactly - In one side, you are saying: you don't want to use profile related values and other side you are saying: you'll need to run with specific values (do you mean runtime values or test specific values).
Now, To answer your 1st question:
1) Either i Mock the Property File for Unit Test:
you can instantiate and load a property file(test specific) and keep the required values there in that file.
2) Or during run time i change the property file parameter values:
you can mock specific property keys with values. like below:
public void shouldBuyBread() throws Exception {
//given
given(mypropertyUtil.getProperty("NUMBER_OF_BREADS")).willReturn(10);
//when
Goods goods = shop.buyBread();
//then
assertThat(goods, containBread());
}

Configuring DropWizard Programmatically

I have essentially the same question as here but am hoping to get a less vague, more informative answer.
I'm looking for a way to configure DropWizard programmatically, or at the very least, to be able to tweak configs at runtime. Specifically I have a use case where I'd like to configure metrics in the YAML file to be published with a frequency of, say, 2 minutes. This would be the "normal" default. However, under certain circumstances, I may want to speed that up to, say, every 10 seconds, and then throttle it back to the normal/default.
How can I do this, and not just for the metrics.frequency property, but for any config that might be present inside the YAML config file?
Dropwizard reads the YAML config file and configures all the components only once on startup. Neither the YAML file nor the Configuration object is used ever again. That means there is no direct way to configure on run-time.
It also doesn't provide special interfaces/delegates where you can manipulate the components. However, you can access the objects of the components (usually; if not you can always send a pull request) and configure them manually as you see fit. You may need to read the source code a bit but it's usually easy to navigate.
In the case of metrics.frequency you can see that MetricsFactory class creates ScheduledReporterManager objects per metric type using the frequency setting and doesn't look like you can change them on runtime. But you can probably work around it somehow or even better, modify the code and send a Pull Request to dropwizard community.
Although this feature isn't supported out of the box by dropwizard, you're able to accomplish this fairly easy with the tools they give you. Note that the below solution definitely works on config values you've provided, but it may not work for built in configuration values.
Also note that this doesn't persist the updated config values to the config.yml. However, this would be easy enough to implement yourself simply by writing to the config file from the application. If anyone would like to write this implementation feel free to open a PR on the example project I've linked below.
Code
Start off with a minimal config:
config.yml
myConfigValue: "hello"
And it's corresponding configuration file:
ExampleConfiguration.java
public class ExampleConfiguration extends Configuration {
private String myConfigValue;
public String getMyConfigValue() {
return myConfigValue;
}
public void setMyConfigValue(String value) {
myConfigValue = value;
}
}
Then create a task which updates the config:
UpdateConfigTask.java
public class UpdateConfigTask extends Task {
ExampleConfiguration config;
public UpdateConfigTask(ExampleConfiguration config) {
super("updateconfig");
this.config = config;
}
#Override
public void execute(Map<String, List<String>> parameters, PrintWriter output) {
config.setMyConfigValue("goodbye");
}
}
Also for demonstration purposes, create a resource which allows you to get the config value:
ConfigResource.java
#Path("/config")
public class ConfigResource {
private final ExampleConfiguration config;
public ConfigResource(ExampleConfiguration config) {
this.config = config;
}
#GET
public Response handleGet() {
return Response.ok().entity(config.getMyConfigValue()).build();
}
}
Finally wire everything up in your application:
ExampleApplication.java (exerpt)
environment.jersey().register(new ConfigResource(configuration));
environment.admin().addTask(new UpdateConfigTask(configuration));
Usage
Start up the application then run:
$ curl 'http://localhost:8080/config'
hello
$ curl -X POST 'http://localhost:8081/tasks/updateconfig'
$ curl 'http://localhost:8080/config'
goodbye
How it works
This works simply by passing the same reference to the constructor of ConfigResource.java and UpdateConfigTask.java. If you aren't familiar with the concept see here:
Is Java "pass-by-reference" or "pass-by-value"?
The linked classes above are to a project I've created which demonstrates this as a complete solution. Here's a link to the project:
scottg489/dropwizard-runtime-config-example
Footnote: I haven't verified this works with the built in configuration. However, the dropwizard Configuration class which you need to extend for your own configuration does have various "setters" for internal configuration, but it may not be safe to update those outside of run().
Disclaimer: The project I've linked here was created by me.
I solved this with bytecode manipulation via Javassist
In my case, I wanted to change the "influx" reporter
and modifyInfluxDbReporterFactory should be ran BEFORE dropwizard starts
private static void modifyInfluxDbReporterFactory() throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("com.izettle.metrics.dw.InfluxDbReporterFactory"); // do NOT use InfluxDbReporterFactory.class.getName() as this will force the class into the classloader
CtMethod m = cc.getDeclaredMethod("setTags");
m.insertAfter(
"if (tags.get(\"cloud\") != null) tags.put(\"cloud_host\", tags.get(\"cloud\") + \"_\" + host);tags.put(\"app\", \"sam\");");
cc.toClass();
}

Which type of resource file to use to store constants

I am developing an application that tests web Services, and I use JUnit parameterized tests. I want to read parameters from a resources file.
I am wondering which is the best way to store these parameters.
In a .properties file ?
test1.inputPath= C:\\Path
test1.expectedOutputPath= C:\\Path
test2.inputPath= C:\\Path2
test2.expectedOutputPath= C:\\Path2
In an xml file?
<test>
<inputPath> C:\Path <\inputPath>
<expectedOutputPath> C:\Path <\expectedOutputPath>
<\test>
<test>
<inputPath> C:\Path2 <\inputPath>
<expectedOutputPath> C:\Path2 <\expectedOutputPath>
<\test>
Other way to do this?
Thanks.
Do not try to make your life more complicated ;) You can easily read property files in this way:
Properties prop = new Properties();
InputStream input = new FileInputStream(fileName);
prop.load(input);
String s = prop.getProperty("test1.inputPath");
and import:
import java.util.Properties;
is it still complicated for you?
The best solution that I found for my problem is to use PropertiesConfiguration of Apache Commons Configuration. It is very simple to use:
In my .properties file :
test1= Path1,Path2
test2= Path3,Path4
Then I read the .properties file automatically and I retrieve paths as a String array for each test.
#Parameters
public static Collection<Object[]> readPropertiesFile(){
ArrayList<Object[]> result= new ArrayList<Object[]>();
try {
Configuration config = new PropertiesConfiguration("testPaths.properties");
Iterator<String> keys=config.getKeys();
while(keys.hasNext()){
String[] paths= config.getStringArray(keys.next());
result.add(paths);
}
} catch (ConfigurationException e) {
e.printStackTrace();
}
return result;
}
The answer is, of course, there are MANY ways of doing it.
First ask yourself: do these properties will change? Are they parameters or are they constants?
For example, the number of the states, what are the chances they will change? In this case you need a constant, not a parameter.
Now, if you are looking for something that can changed at runtime then you should look into properties and resource bundles.
If all you need are constants, then you can do something like:
public interface Constants
{
public char NUMBER_ONE = '1';
public long A_LONG_TIME_AGO = 1321322;
public String CANT_BREAK_WITH_IRON_PICKAXE= "OBSIDIAN";
}
There are many advantages in using interfaces: they don't need to be instantiated, won't slow down your system with IO access, and all attributes are static final.
However, if you need to load the values during runtime, then use properties files. Although all answers here are good, the only one I consider good enough is Spring's #Configuration and #ImportResource, which are injected, allow for nice mocking, and integrate nicely with the rest of the Spring framework, and can be easily overridden with -D from the command line.
Example on how to load properties files using a mix of xml and properties files: Spring-Boot: How do I reference application.properties in an #ImportResource

How can I find the time of property files gets loaded by Spring

I am replacing the property factory which is used to the load the configuration files with spring. So technically now, my configuration files should be loaded using spring DI via Apache
commons configurations.
So far I have created an Action class and a POJO view class which has the getters and setters for Loadtime, FileModified time, File name etc. The Action has a list of configuration classes injected into the constructor and in the execute method I am looping over the configuration classes creating a simple view object for each one. Then I am setting the value to the my view object which I get from config something like this:
public final String execute() {
configViewList = new ArrayList<ConfigurationViewObject>();
if ((this.configurationList != null) && (this.configurationList.size() != 0)) {
for (PropertiesConfiguration config : configurationList) {
ConfigurationViewObject view = new ConfigurationViewObject();
view.setFileName(config.getFileName());
view.setFileModificationTime(new Date(config.getFile().lastModified()));
configViewList.add(view);
}
return SUCCESS;
} else {
addActionError("List is null.");
return Action.ERROR;
}
}
Well, now I want to find out the load time. Any idea how to find the time when the spring loads the file.I have entirely searched PropertiesConfiguration class and File class if there is any method which gets it for me, however couldn't find any. I would appreciate the much awaited help.
Its very tricky to find this because Spring will never expose this to outside world and thats correct, why would anyone want to know when config file gets loaded?
But still , here is what i would do. Spring config will be loaded when Spring creates loads a class which needs some properties to be set [This is not document officially anywhere but thats how it shld be logically]. Now next part is to find out which class instance needing properties is created first. Again no starighforward way for this but still an appox. way would be to put a System.currentTimeMillis() in Class's constructor. So this will give you an appox. time of when property file will be loaded.
For a straightforward way to do this... you can try calling long before = System.currentTimeMillis() before the call to retrieve properties, and another long after = System.currentTimeMillis() call right after the the properties are retrieved, and seeing the value of the difference, after - before.

Categories

Resources