Reputation: 11176
Let's say I have the following setup
application-toyota.properties
model=prius
type=hybrid
application-chevy.properties
model=volt
type=electric
classes:
public class Car{
@Value("${model}")
private String model;
@Value("${type}")
private String type;
...setters & getters...
}
and
public class CarFactory{
private Car car;
public Car makeCar(String profile){
return car;
}
}
Is there a way make the makeCar method accept a profile, say "toyota", construct a Car object dynamically while filling in the values from the appropriate property file (application-toyota.properties) in this case and return a valid Car object?
Upvotes: 0
Views: 699
Reputation: 5937
I think I understand what you're trying to do, but you're mixing up the terminology. If your goal is to create a single Application that supports a single type of car, then Mark's answer is what you're going for. If, however, what you are looking for is a Factory that creates multiple types of cars with different configurations, for which you do not know at compile/start-up time what they are, you need to approach the idea differently.
In this version, we would have multiple "types" of Cars defined in a profile, so we'd have a POJO Car Class.
public class Car {
private String model;
private String type;
public Car() {
}
public Car(String model, String type) {
this.model = model;
this.type = type;
}
}
We'd then have your CarFactory, only because we have multiple configurations for the Factory, we'd handle them in a map.
public class CarFactory {
Map<String, ConfiguredCarFactory> factories = new HashMap<>();
public Car makeCar(String profile) {
return getFactory(profile).makeCar();
}
private ConfiguredCarFactory getFactory(String profile) {
ConfiguredCarFactory carFactory = factories.get(profile);
if(carFactory == null) {
carFactory = new ConfiguredCarFactory(profile);
factories.put(profile, carFactory);
}
return carFactory;
}
}
In this case, the profile I am using for simplicity was the actual file location of the properties file. This isn't set up as a Bean, but it can be very quickly if you want to create a Bean to handle the map's functions under the cover.
Then, finally, we'd have a configured CarFactory doing the actual car creation, by profile.
public class ConfiguredCarFactory {
private final String profile;
private String model;
private String type;
public ConfiguredCarFactory(String profile) {
this.profile = profile;
Properties prop = new Properties();
File file = new File(profile);
try(FileInputStream input = new FileInputStream(profile)) {
prop.load(input);
model = (String) prop.get("model");
type = (String) prop.get("type");
} catch (Exception e) {
e.printStackTrace();
model = "Generic";
type = "Generic";
}
}
public Car makeCar() {
return new Car(model, type);
}
}
While this certainly meets your requirements, I am somewhat hesitant to say this is what you're looking for. Providing an unknown number of car configurations as properties is less ideal than, say, storing all the car configurations in a database and instantiating as Entities through JPA. This is much more "dynamic" and would more closely follow the design philosophy of Spring than something that is relatively rigid and requires the existence of configuration files on the machine in addition to some unknown input ofr the file source.
Upvotes: 1
Reputation: 42551
I think you should clarify the question more. I'll explain
In Spring profiles are specified at the very beginning (usually via parameters of execution of spring-driven application).
In this example, it doesn't make sense to activate both profiles simultaneously because they will "compete" for actual values of properties "model" and "type".
From this, I conclude that you activate only one profile.
Now if the profile, say, "toyota" is active, the values for the car object are well defined, so you don't even need a Car factory - spring will read the relevant property file (application-toyota.properties in this case), resolve the values of properties and will inject the correct values to the car bean, which is also driven by spring. Of course, the same holds for "chev" profile as well.
Upvotes: 1