I am trying to create my own validator for validating a List<String> read from a YAML configuration file. What I want to do, is validate it against a Enum class that I have created which looks like the following:
public enum BundleName {
DK("dk.bundle"),
UK("uk.bundle"),
US("us.bundle"),
DK_DEBUG("dk.bundle.debug"),
UK_DEBUG("uk.bundle.debug"),
US_DEBUG("us.bundle.debug"),
;
private String bundleName;
BundleName(String bundleName) {
this.bundleName = bundleName;
}
public String getBundleName() {
return this.bundleName
}
}
My YAML file has the following defined:
bundleNames:
- ${DK}
- ${UK}
- ${US}
- ${DK_DEBUG}
- ${UK_DEBUG}
- ${US_DEBUG}
Now either some of these environment variables might be set or all of them might be set or just one is set. Different environment different combo. Anyway what I want is to be able to validate these environment variables against the bundleName in enum BundleName.class. Now Hibernate have a nice example, and also all other examples I find on the net is, where validation is done against a specific simple enum. I do not want to check on the enum name but the enum value, and I simply cannot figure out how. All what I have tried so fare is some combinations of what I found in some other posts like this and this and many more.
In my ApiConfiguration.java I would like to end up with something like the following on my list read from YAML:
#NotNull
#BundleNameValidation(acceptedValues = BundleName.class)
private List<String> bundleNames;
If that is possible somehow.
Related
I'm creating a Yaml configuration reader. I'm having some problems to get the values
from sections. I have already created a way to read not sectioned-keys but when a section like
Test:
Yes:
True: a
False: b
No:
True:
Default: c
False: d
is on the yml file, I want to add the path of the values to a HashMap. In the case above,
the path in the HashMap would be
Test.Yes.True = a
Test.Yes.False = b
Test.No.True.Default = c
Test.No.False = d
notice that Yes and No are sections inside Test. True and False values are inside the section Yes that is in Test etc.
I have no idea how read like the block above.
First of all, you should show what you have tried and where you failed. That helps us to provide very specific answer to your question.
For now, Try converting yaml to corresponding Java POJO. You can do this directly or in steps. You can do it by yourself or can use online converters.
Firstly, you can convert from yaml file to Json. https://www.json2yaml.com/
then with the json, you can create Java POJO's. http://pojo.sodhanalibrary.com/ OR http://www.jsonschema2pojo.org/
The converted json to java POJO will automatically create proper mapping format for you and then you can easily use them.
for your most nested "Default" value case, you can take HashMap with name "HashMap<String, String> trueHashMap = new HashMap<String, String>()" if you wish, otherwise a new POJO with "True.java" will also work".
public class True
{
private String false;
private String true;
// getters setters
}
And then, You need to do some research to map them and pick the configuration.
NOTE:
You can do it by multiple online converters. I have provided only the popular ones.
I've generated a document using spring auto rest docs. This uses capital.scalable libraries combined with java docs and spring rest docs.
My issue is with the List of enums while describing the request fields.
Type column generates a value as Array[Object]. Also, the description column doesn't generate the must be one of statement with the enum values, as it does when only Enum is the field and not the list of enums.
public enum Discipline {
ECONOMICS("economics"),
SOCIOLOGYANTHROPOLOGY("sociologyanthropology");
private final String discipline;
Discipline(final String discipline) {
this.discipline = discipline;
}
public String getId() {
return discipline;
}
}
Above is the enum that I have. It uses tostring correctly to display in the description when the field is used only as enum. But if list of enums i.e.
List<Discipline>
is the field, then it doesn't describe properly as mentioned above.
Please let me know what should be done to generate the document more effectively?
You are right that lists of enums are not properly supported yet.
If you have a request/response like:
class SomeRequest {
public enum EnumTest {
ONE, TWO
}
/**
* List of enums
*/
private List<EnumTest> enumTestList;
}
it is documented as
with Spring Auto REST Docs at the moment.
It would be good if the type would be Array[String] and the description would list the elements of the enum, e.g. "Elements must be one of [...]".
Spring Auto REST Docs 1.0.11 fixes the type issue and thus Array[String] will be shown with this version.
I opened an issue to improve the documentation of lists of enums: https://github.com/ScaCap/spring-auto-restdocs/issues/194. Until this issue is resolved, one can manually add "Elements must be one of [...]" to the Javadoc of the list as a workaround.
I am working on a JAVA web service with mongo, In order to implement mongo java driver POJO api (like Morphia), I establish my POJO like the following:
public class User {
public static final String USER_NAME = "userName";
private String userName;
public User() {
}
// getter && setter //
}
USER_NAME = "userName" is a reference for future use as a filed name. What I'm trying to achieve is that I could use a simple if to check if received data equals to the field name. For example :
User user = new User();
String receivedData = httpRequest.getParameter(User.USER_NAME);
if (receivedData == null) {
return null;
} else {
user.setUserName(receivedData);
userCollection.insertOne(user);
// userCollection is MongoCollection<User>
return Gson().toJson(user);
}
I am looking for a eclipse function or plug in that could auto generate one of the declaration (USER_NAME = "userName" and private String userName) by the other and make sure the consistency of the code.
Of course, that would be appreciated if there's any suggestion for a better practice.
EDIT
Stephan's reflection approach gives a great flexibility for the code. However, compare to my original simplified example, the real situation might be more complex. For example, one httpRequest has many different parameters which are stored in different(n) POJO and each POJO has many different(n) fields. In that case, we will do n*n loop for just getting the field value.
If you want to do the same for all fields of the POJO, consider iterating the result of User.class.getFields(). For each Field get the name (f.getName()), use the name to retrieve the value and set it to the field (f.set(object,value)). With this approach there's no need for a constant like USER_NAME.
EDIT 1: If performance is an issue you may of course collect all those fields into some collection up-front once and for all, but then the bottleneck will remain at having to try httpRequest.getParameter() for each possible field. Nothing specific to the reflective approach.
EDIT 2: In a "nicer" language there could be type checked syntax for retrieving a Field instance, e.g., imagine (not Java):
Field f = User::userName;
This answer basically demonstrates that generating redundant constants is not strictly necessary, since the thing that consistently connects the name to the field already exists, it's a Field.
I've got a Spring #RequestMapping with a couple of #PathVariables, and the first one is necessary to narrow down to the second one - you can see in the example below that I need to get the Department in order to get the Module. Using plain String #PathVariables I can do it like this:
#RequestMapping("/admin/{dept}/{mod}/")
public String showModule(#PathVariable String dept, #PathVariable String mod) {
Department department = dao.findDepartment(dept);
Module module = department.findModule(mod);
return "view";
}
But I'm keen to use Spring's Converter API to be able to specify the Department directly as the #PathVariable. So this works after I've registered a custom Converter class:
#RequestMapping("/admin/{dept}/")
public String showDept(#PathVariable Department dept) {
return "view";
}
But the Converter API doesn't give access outside of the single argument being converted, so it's not possible to implement the Converter for Module. Is there another API I can use? I'm eyeing up HandlerMethodArgumentResolver - has anyone solved a problem like this, or are you sticking to String #PathVariables?
I'm using Spring 3.1.
I haven't done it like this but one way I thought of was to make a separate converter for the both of them:
#RequestMapping("/admin/{deptAndModule}/")
public String showDept(#PathVariable DepartmentAndModule deptAndModule) {
return "view";
}
And have the converter able to take an input of the form "deptid-modid" e.g. "ch-c104". It wouldn't be possible to separate them with a slash as the request wouldn't match the RequestMapping pattern of /admin/*/.
In my case, the requirements have changed slightly so that module codes are fully unique and don't need to be scoped to department. So I don't need to do this any more. If I did, I would probably eschew the automatic Module conversion and do it manually in the method.
Sadly, I forgot to take the code from work with me today. But maybe this little example will clarify things.
I use hibernate to map a bean to a table.
Example:
import javax.persistence.column;
….
String columnameA;
….
#Column(name="columnameA")
public String getColumname(){
return columnameA
}
….
I do not want to hardcode the columnname (“columnameA”) in my sourcecode, because I need to switch the columname without building the entire project.
I wanted to use something like:
#Column(name=getColumnName())
This does not work. The idea is, to to write the columnname somewhere in the jndi tree and use it at startup. So i only need to restart the application to change the columnname.
The only way around this problem – which I can think of – is to write my own annotation, which extends the hibernate class. Is there a simpler way of doing this?
You can't achieve this with annotations, but a solution to your specific problem is to implement a custom NamingStrategy:
public class NamingStrategyWrapper implements NamingStrategy {
private NamingStrategy target;
public NamingStrategyWrapper(NamingStrategy target) {
this.target = target;
}
public String columnName(String arg0) {
if ("columnameA".equals(arg0)) return getColumnName();
else return target.columnName(arg0);
}
...
}
-
AnnotationConfiguration cfg = new AnnotationConfiguration();
cfg.setNamingStrategy(new NamingStrategyWrapper(cfg.getNamingStrategy()));
factory = cfg.configure().buildSessionFactory();
The only values you can assign to attributes are constant values, specified by hand, or stored in public static final variables.
Annotations do not define behavior, but only meta-informations about class, methods and the likes. You can specify behavior in annotation processors, that read your annotations and generate new source code or other files.
Writing an annotation processo is beyond my knowledge, but you could find other information in the Annotations Processing Tool guide by Sun.