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?
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.
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.
Related
Is there some way in Spring Boot that I can perform validation on properties that depend on each other's values, and have the error message be associated with the property?
I want to return the errors to the user in a nice JSON structure:
{
"errors": {
"name": "is required if flag is true"
}
}
Example:
#Entity
public class MyEntity {
private boolean nameRequiredFlag;
// Required if "nameRequiredFlag" is set to true:
private String name;
}
One solution that doesn't solve my problem of associating the error message with the name property is to create a validator annotation for the entity:
#ValidEntity
public class MyEntity {
private boolean nameRequiredFlag;
// Required if "nameRequiredFlag" is set to true:
private String name;
}
#Constraint( validatedBy = { MyEntityValidator.class } )
#Documented
#Target( { ElementType.TYPE } )
#Retention( RetentionPolicy.RUNTIME )
public #interface ValidEntity{
Class<?>[] groups () default {};
String message () default "name is required if 'nameRequiredFlag' is true";
Class<? extends Payload>[] payload () default {};
}
public class MyEntityValidator implements Validator<ValidEntity, MyEntity> {
#Override
public boolean isValid ( MyEntity entity, ConstraintValidatorContext context ) {
if ( !entity.nameRequiredFlag ) return true;
return !StringUtils.isBlank( entity.getName() );
}
}
This is laughably cumbersome and doesn't solve my problem. Isn't there any way I can do this with the framework validation?
Edit: This is for a JSON API, and the consumer really needs to be able to associate the error message to a best guess at which field has an issue. It is not helpful to send the consumer an error message for the whole object, or a computed property.
Solution given by #EvicKhaosKat is one way of doing it. However, when there are too many fields dependent on each other in a complicated way, your class becomes full of annotations and I personally struggle a lot relating them.
A simpler approach is to create a method(s) in your pojo which does the cross field validations and returns a boolean. On the top of this method annotate it with #AssertTrue(message = "your message"). It will solve your problem in a cleaner fashion.
public class SampleClass {
private String duration;
private String week;
private String month;
#AssertTrue(message = "Duration and time attributes are not properly populated")
public boolean isDurationCorrect() {
if (this.duration.equalsIgnoreCase("month")) {
if (Arrays.asList("jan", "feb", "mar").contains(month))
return true;
}
if (this.duration.equalsIgnoreCase("week")) {
if (Arrays.asList("1-7", "8-15", "16-24", "25-31").contains(week))
return true;
}
return false;
}
}
Note: I have not tested this code but have used this approach in multiple places and it works.
Possible reason is that name validation operates on not-yet-fully constructed object, so nameRequiredFlag is not filled yet.
As an option there is a #GroupSequence annotation, which allows to group and perform validations in an order you specify.
For example it is possible to add to MyEntity annotations:
#ValidEntity(groups = DependentValidations.class)
#GroupSequence({MyEntity.class, DependentValidations.class})
So all the other validation annotations on MyEntity class gonna be performed first, and after that DependentValidations group, which consists of ValidEntity.
Thus ValidEntity will be called on fully created object, and the last in order.
(DependentValidations.class - just an empty interface created somewhere nearby, like any other marker interface)
https://www.baeldung.com/javax-validation-groups will possibly describe that in much more details.
p.s. answer provided by #Innovationchef will possibly suit the case more :)
We are creating a REST API which is documented using Swagger's #ApiModelProperty annotations. I am writing end-to-end tests for the API, and I need to generate the JSON body for some of the requests. Assume I need to post the following JSON to an endpoint:
{ "name": "dan", "age": "33" }
So far I created a separate class containing all the necessary properties and which can be serialized to JSON using Jackson:
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyPostRequest {
private String name;
private String age;
// getters and fluid setters omitted...
public static MyPostRequest getExample() {
return new MyPostRequest().setName("dan").setAge("33");
}
}
However, we noticed that we already have a very similar class in the codebase which defines the model that the API accepts. In this model class, the example values for each property are already defined in #ApiModelProperty:
#ApiModel(value = "MyAPIModel")
public class MyAPIModel extends AbstractModel {
#ApiModelProperty(required = true, example = "dan")
private String name;
#ApiModelProperty(required = true, example = "33")
private String age;
}
Is there a simple way to generate an instance of MyAPIModel filled with the example values for each property? Note: I need to be able to modify single properties in my end-to-end test before converting to JSON in order to test different edge cases. Therefore it is not sufficient to generate the example JSON directly.
Essentially, can I write a static method getExample() on MyAPIModel (or even better on the base class AbstractModel) which returns an example instance of MyAPIModel as specified in the Swagger annotations?
This does not seem to be possible as of the time of this answer. The closest possibilities I found are:
io.swagger.converter.ModelConverters: The method read() creates Model objects, but the example member in those models is null. The examples are present in the properties member in String form (taken directly from the APIModelParameter annotations).
io.swagger.codegen.examples.ExampleGenerator: The method resolveModelToExample() takes the output from ModelConverters.read(), and generates a Map representing the object with its properties (while also parsing non-string properties such as nested models). This method is used for serializing to JSON. Unfortunately, resolveModelToExample() is private. If it were publicly accessible, code to generate a model default for an annotated Swagger API model class might look like this:
protected <T extends AbstractModel> T getModelExample(Class<T> clazz) {
// Get the swagger model instance including properties list with examples
Map<String,Model> models = ModelConverters.getInstance().read(clazz);
// Parse non-string example values into proper objects, and compile a map of properties representing an example object
ExampleGenerator eg = new ExampleGenerator(models);
Object resolved = eg.resolveModelToExample(clazz.getSimpleName(), null, new HashSet<String>());
if (!(resolved instanceof Map<?,?>)) {
// Model is not an instance of io.swagger.models.ModelImpl, and therefore no example can be resolved
return null;
}
T result = clazz.newInstance();
BeanUtils.populate(result, (Map<?,?>) resolved);
return result;
}
Since in our case all we need are String, boolean and int properties, there is at least the possibility to parse the annotations ourselves in a crazy hackish manner:
protected <T extends MyModelBaseClass> T getModelExample(Class<T> clazz) {
try {
T result = clazz.newInstance();
for(Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(ApiModelProperty.class)) {
String exampleValue = field.getAnnotation(ApiModelProperty.class).example();
if (exampleValue != null) {
boolean accessible = field.isAccessible();
field.setAccessible(true);
setField(result, field, exampleValue);
field.setAccessible(accessible);
}
}
}
return result;
} catch (InstantiationException | IllegalAccessException e) {
throw new IllegalArgumentException("Could not create model example", e);
}
}
private <T extends MyModelBaseClass> void setField(T model, Field field, String value) throws IllegalArgumentException, IllegalAccessException {
Class<?> type = field.getType();
LOGGER.info(type.toString());
if (String.class.equals(type)) {
field.set(model, value);
} else if (Boolean.TYPE.equals(type) || Boolean.class.equals(type)) {
field.set(model, Boolean.parseBoolean(value));
} else if (Integer.TYPE.equals(type) || Integer.class.equals(type)) {
field.set(model, Integer.parseInt(value));
}
}
I might open an Issue / PR on Github later to propose adding functionality to Swagger. I am very surprised that nobody else has seemed to request this feature, given that our use case of sending exemplary model instances to the API as a test should be common.
Consider the following pojo for reference:
public class User{
private String username;
private String firstName;
private String middleName;
private String lastName;
private String phone;
//getters and setters
}
My application is a basically spring-boot based REST API which exposes two endpoints, one to create the user and the other to retrieve a user.
The "users" fall into certain categories, group-a, group-b etc. which I get from the headers of the post request.
I need to validated the user data in runtime and the validations may differ based on the group of a user.
for example, the users that fall into group-a may have phone numbers as an optional field whereas it might be a mandatory field for some other group.
The regex may also vary based on their groups.
I need to be able to configure spring, to somehow dynamically validate my pojo as soon as they are created and their respective set of validations get triggered based on their groups.
Maybe I can create a yml/xml configuration which would allow me to enable this?
I would prefer to not annotate my private String phone with #NotNull and #Pattern.
My configuration is as follows:
public class NotNullValidator implements Validator {
private String group;
private Object target;
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
#Override
public void validate(Object o) {
if (Objects.nonNull(o)) {
throw new RuntimeException("Target is null");
}
}
}
public interface Validator {
void validate(Object o);
}
#ConfigurationProperties(prefix = "not-null")
#Component
public class NotNullValidators {
List<NotNullValidator> validators;
public List<NotNullValidator> getValidators() {
return validators;
}
public void setValidators(List<NotNullValidator> validators) {
this.validators = validators;
}
}
application.yml
not-null:
validators:
-
group: group-a
target: user.username
-
group: group-b
target: user.phone
I want to configure my application to somehow allow the validators to pick their targets (the actual objects, not the strings mentioned in the yml), and invoke their respective public void validate(Object o) on their targets.
P.S.
Please feel free to edit the question to make it better.
I am using jackson for serializing and deserializing JSON.
The easiest solution to your problem, as i see it, is not with Spring or the POJOs themselves but with a design pattern.
The problem you're describing is easily solved by a strategy pattern solution.
You match the strategy to use by the header you're expecting in the request, that describes the type of user, and then you perform said validations inside the strategy itself.
This will allow you to use the same POJO for the whole approach, and deal with the specifics of handling/parsing and validating data according to the each type of user's strategy.
Here's a link from wiki books with a detailed explanation of the pattern
Strategy Pattern
Suppose you have a basic interface for your strategies:
interface Strategy {
boolean validate(User user);
}
And you have 2 different implementations for the 2 different types of user:
public class StrategyA implements Strategy {
public boolean validate(User user){
return user.getUsername().isEmpty();
}
}
public class StrategyB implements Strategy {
public boolean validate(User user){
return user.getPhone().isEmpty();
}
}
You add a Strategy attribute to your User POJO and assign the right implementation of the Strategy to that attribute when you receive the post request.
Everytime you need to validate data for that user you just have to invoke the validate method of the assigned strategy.
If each User can fit multiple strategies, you can add a List<Strategy> as an attribute instead of a single one.
If you don't want to change the POJO you have to check which is the correct strategy every time you receive a post request.
Besides the validate method you can add methods to handle data, specific to each strategy.
Hope this helps.
You can use validation groups to control which type of user which field gets validated for. For example:
#NotBlank(groups = {GroupB.class})
private String phone;
#NotBlank(groups = {GroupA.class, GroupB.class})
private String username;
Then you use the headers from the request that you mentioned to decide which group to validate against.
See http://blog.codeleak.pl/2014/08/validation-groups-in-spring-mvc.html?m=1 for a complete example.
Updated to include a more comprehensive example:
public class Val {
private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
public boolean isValid(User user, String userType) {
usergroups userGroup = usergroups.valueOf(userType);
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user, userGroup.getValidationClass());
return constraintViolations.isEmpty();
}
public interface GroupA {}
public interface GroupB {}
public enum usergroups {
a(GroupA.class),
b(GroupB.class);
private final Class clazz;
usergroups(Class clazz) {
this.clazz = clazz;
}
public Class getValidationClass() {
return clazz;
}
}
}
This doesn't use application.yaml, instead the mapping of which fields are validated for each group is set in annotations, similar results using Spring's built in validation support.
I was able to solve my problem with the use of Jayway JsonPath.
My solution goes as follows:
Add a filter to your API which has the capability to cache the InputStream of the ServletRequest since it can be read only once. To achieve this, follow this link.
Create a bunch of validators and configure them in your application.yml file with the help of #ConfigurationProperties. To achieve this, follow this link
Create a wrapper which would contain all your validators as a list and initialize it with #ConfigurationProperties and the following configuration:
validators:
regexValidators:
-
target: $.userProfile.lastName
pattern: '[A-Za-z]{0,12}'
group: group-b
minMaxValidators:
-
target: $.userProfile.age
min: 18
max: 50
group: group-b
Call the validate method in this wrapper with the group which comes in the header, and then call the validate of the individual validators. To achieve this, I wrote the following piece of code in my wrapper:
public void validate(String input, String group) {
regexValidators.stream()
.filter(validator -> group.equals(validator.getGroup()))
.forEach(validator -> validator.validate(input));
minMaxValidators.stream()
.filter(validator -> group.equals(validator.getGroup()))
.forEach(validator -> validator.validate(input));
}
and the following method in my validator:
public void validate(String input) {
String data = JsonPath.parse(input).read(target);
if (data == null) {
throw new ValidationException("Target: " + target + " is NULL");
}
Matcher matcher = rule.matcher(data);
if (!matcher.matches()) {
throw new ValidationException("Target: " + target + " does not match the pattern: " + pattern);
}
}
I have created a functioning project to demonstrate the validations and it can be found here.
I understand that the answer alone might not be very clear, please follow the above mentioned url for the complete source code.
I have a java api which performs an external resource lookup and then maps the values to a Pojo. To do this, the api needs the field names of the Pojo as string values, something like:
public <F> F populatePojoFields(String primaryField, String secondaryField);
This works fine, however passing the pojo field names as String to the api does not feel right. I was able to change this by writing marker annotations for the pojo, so now it is like
public class POJO {
#Primary //custom marker annotation
private int mojo;
#Secondary //custom marker annotation
private String jojo;
}
String primaryField = getFieldNameUsingReflection(Pojo.class, Primary.class)
String secondryField = getFieldNameUsingReflection(Pojo.class, Secondary.class)
Pojo pojo = populatePojoFields(primaryField, secondaryField);
This way I don't have to keep track of string values, I can just add marker annotations to the Pojo fields. This works fine, but I'm worried about performance. Is this a standard way to do things? as keeping hardcoded string values is more efficient than looking up the field names every time we need to call the api. Is there a better way to do this?
If you call getFieldNameUsingReflection often you can think to cache the result of this call.
You can use a singleton class with internal Map with a code like the following:
public class SingletonMapPrimarySecondary {
Map<Class, String> mapPrimary;
Map<Class, String> mapSecondary;
// TODO: Handle mapPrimary and mapSecondary creation and singleton pattern
public String getPrimary(Class clazz) {
String primary = mapPrimary.get(clazz);
if (primary == null) {
primary = getFieldNameUsingReflection(clazz, Primary.class);
mapPrimary.put(clazz, primary);
}
return primary;
}
public String getSecondary(Class clazz) {
// TODO: Similar to getPrimary
}
}
Looking for some guidance on designing some code in Java.
Currently I have something like this....
#Service
class SomeService {
#Autowired
private FilterSoldOut filterSoldOut;
#Autowired
private FilterMinPriceThreshold filterMinPriceThreshold;
public List<Product> getProducts() {
List<Product> products = //...code to get some products
// Returns list of in-stock products
products = filterSoldOut.doFilter(products);
// Returns list of products above min price
products = filterMinPriceThreshold.doFilter(minPrice, products);
return products;
}
}
What I would like to be able to do is create a Filter interface with a doFilter method and then in SomeService create a List filters, which is autowired by Spring. Then in the getProducts method I can iterate the filters list and invoke doFilter. This way in the future I can, create new classes that implement the Filter interface and add them to the list via Spring configuration, and have the new filter applied without having to change the code.
But, the problem is that the parameters to the doFilter method can be different. I've read about the Command Pattern, and the Visitor Pattern but they don't quite seem to fit the bill.
Can anyone suggest a good pattern to achieve what I've described?
Thanks.
There are many ways to do this. Some are complicated, some are simpler. The simplest one would be to use varargs or an array of Object elements. The problem here is that you have to cast each objetc to its proper type in order to use them and that can be a little tricky if there are multiple types in an unknown order.
Another option is to use a Map<String,Object> (which you can wrap in a class of your own if required, something lile FilterParams) that stores parameters based on a name, and you can then obtain them and cast them accordingly.
Edit
Considering that the parameters vary on runtime, you'll need someone "well informed" about the current configuration.
Not pattern-wise but I'd rather keep it simple without using too many fancy names. What about introducing a FilterConfigurator that has a simple overloaded method configure that recieves the particular filter and configures it based on its type?. This configurator is the informed entity that knows the current values for those parameters.
The goal is to rid Service from the responsibility of configuring a filter.
In addition, if you create your Filter class, you'll be able to implement a single doFilter that you can invoke without changes.
There's another Idea... and it involves a FilterFactory that creates and initializes filters, thus having a filter 100% configured from scratch. This factory can rely on the very same FilterConfigurer or do it itself.
old:
I'd suggest you setting the filter state at construction time or at
least before you getProducts().
In your example with the two filters one of them is (probably)
checking a database for availability of the product and the other one
is comparing the product's price to some preset value. This value
(minPrice) is known before the filter is applied. It can
also be said that the filter depends on it, or that it's part of the
filter's state. Therefore I'd recommend you putting the
minPrice inside the filter at construction time (or via a
setter) and then only pass the list of products you want to filter.
Use the same pattern for your other filters.
new suggestion (came up with it after the comments):
You can create a single object (AllFiltersState) that holds all the values for all the filters. In your controller set whatever criteria you need in this object (minPrice, color, etc.) and pass it to every filter along the products - doFilter(allFiltersState, products).
As Cris say you can use next function definition:
public List<Product> doFilter(Object...args) {
if (args.length != 2)
throw new IllegalArgumentException();
if (! (args[0] instanceof String))
throw new IllegalArgumentException();
if (! (args[2] instanceof Integer))
throw new IllegalArgumentException();
String stringArgument = (String) args[0];
Integer integerArgument = (Integer) args[1];
// your code here
return ...;
}
or with command pattern:
public interface Command {
}
public class FirstCommand implements Command {
private String string;
// constructor, getters and setters
}
public class SecondCommand implements Command {
private Integer integer;
// constructor, getters and setters
}
// first service function
public List<Product> doFilter(Command command) {
if (command instanceof FirstCommand)
throw new IllegalArgumentException();
FirstCommand firstCommand = (FirstCommand) command;
return ...;
}
// second service function
public List<Product> doFilter(Command command) {
if (command instanceof SecondCommand)
throw new IllegalArgumentException();
SecondCommand secondCommand = (SecondCommand) command;
return ...;
}
EDIT:
Ok, i understand your question. And think you can create various session scoped filters.
#Service
class SomeService {
#Autowired(required = false)
private List<Filter> filters;
public List<Product> getProducts() {
List<Product> products = //...code to get some products
if (filters != null) {
for (Filter filter : filters)
products = filter.doFilter(products);
}
return products;
}
}
And then create filters with settings fields:
public PriceFilter implements Filter {
private Integer minPrice;
private Integer maxPrice;
// getters and setters
public List<Product> doFilter(List<Product> products) {
// implementation here
}
}
public ContentFilter implements Filter {
private String regexp;
// getters and setters
public List<Product> doFilter(List<Product> products) {
// implementation here
}
}
Then user can configure this filters for session and use service function getProducts to get result.
Having a list of filters getting autowired is not a very good approach to solve your problem.
Every filter depends on different types of parameters which would need to be passed to the doFilter method. Needing to do so makes the approach highly unflexible. Yes you could use varargs but it would just create a mess. That's why it's probably easier to implement a builder to build you a chain of filters to be applied to the collection of products. Adding new filters to the builder becomes a trivial task. The Builder Pattern is very useful when a lot of different parameters are at play.
Consider having this interface:
public interface CollectionFilter<T> {
public Collection<T> doFilter(Collection<T> collection);
}
A filter chaining class which applies all filters to the collection:
public class CollectionFilterChain<T> {
private final List<CollectionFilter<T>> filters;
public CollectionFilterChain(List<CollectionFilter<T>> filters) {
this.filters = filters;
}
public Collection<T> doFilter(Collection<T> collection) {
for (CollectionFilter<T> filter : filters) {
collection = filter.doFilter(collection);
}
return collection;
}
}
The two CollectionFilter<T> implementations:
public class InStockFilter<T> implements CollectionFilter<T> {
public Collection<T> doFilter(Collection<T> collection) {
// filter
}
}
public class MinPriceFilter<T> implements CollectionFilter<T> {
private final float minPrice;
public MinPriceFilter(float minPrice) {
this.minPrice = minPrice;
}
public Collection<T> doFilter(Collection<T> collection) {
// filter
}
}
And a builder to let you build the filter chain in a easy way:
public class CollectionFilterChainBuilder<T> {
List<CollectionFilter<T>> filters;
public CollectionFilterChainBuilder() {
filters = new ArrayList<CollectionFilter<T>>();
}
public CollectionFilterChainBuilder<T> inStock() {
filters.add(new InStockFilter<T>());
return this;
}
public CollectionFilterChainBuilder<T> minPrice(float price) {
filters.add(new MinPriceFilter<T>(price));
return this;
}
public CollectionFilterChain<T> build() {
return new CollectionFilterChain<T>(filters);
}
}
With the builder it's easy to create a filter chain as follows:
CollectionFilterChainBuilder<Product> builder =
new CollectionFilterChainBuilder();
CollectionFilterChain<Product> filterChain =
builder.inStock().minPrice(2.0f).build();
Collection<Product> filteredProducts =
filterChain.doFilter(products);
In a more dynamic settings you could use the builder like:
CollectionFilterChainBuilder<Product> builder = new CollectionFilterChainBuilder();
if (filterInStock) {
builder.inStock();
}
if (filterMinPrice) {
builder.minPrice(minPrice);
}
// build some more