I'm developing an application based on Spring Framerwork. As a view technology I use integrated with the framework Freemarker. Problems occur when java bean that stores data for vizualization have a null in some fields. There is no null conception in Freemarker so it considers that there is no these fields in the bean at all. I suppose problem could be solved by customization of class that copies data from the java bean to freemarker's hash object referred in template. But i haven't found what class does it in Spring. Is there such class and how is it called?
Usually you just deal with nulls directly in the template. E.g:
${person.surname!"n/a"}
which will print "n/a" in case of a null surname, or just:
${person.surname!}
which will print out the empty string (nothing) in case of a null surname.
You can use the "!" operator. Here is an example :
${your_property!""}
It will print the empty string "" if your_property is null.
If any part in your property chain can be null, you can also put parantheses around it to guard against any part being null. E.g. if you pu
${person.car.door.color!"<no value"}
you only guard against the color being null. But if it could also happen that the door, the car or the whole person is gone missing, you have to put
${(person.car.door.color)!"<no value"}
Related
I've an entity with property name qYear. I tried creating a findByIdAndQYear method in repository but that did not work. I ran into IllegalArgumentException: Unable to locate Attribute with the the given name [QYear] on this ManagedType).
However findByIdAndqYear works. Any idea how single letter abbreviations like this are expanded please?
Spring Data (not just the JPA module) base this on the Java Bean Specification.
In order to avoid misinterpretation of the specification this is actually implemented using [java.beans.Introspector][1].
See also https://jira.spring.io/browse/DATACMNS-1589
So I'm writing a springboot application and came across a weird behaviour: If a property name start with is, for example: isIgnoreRequest thymeleaf won't find it but if i change it to ignoreRequest it works.
So my question is: Am I not allowed to have is at the beginning?
Here is some more context:
data class Response(val isIgnoreRequest: Boolean = false,
val name: String = StringUtils.EMPTY)
...
//This is how I add the attribute
//Info = Response object
redirectAttributes.addFlashAttribute(ATTRIBUTE_RESPONSE, info)
With the code above thymeleaf can't find the property:
Property or field 'isIgnoreRequest' cannot be found on object of type ... - maybe not public or not valid?
If I remove the is it works fine. Even though it sounds stupid I think the is is indeed my problem.
Yes, the model attributes can start with is. The issue isn't coming from thymeleaf, but from kotlin (nice job putting it in the tags). Let me explain:
When you reference a model attribute in thymeleaf, it looks for the getter/setter method of that attribute using the normal convention; in your example, for the attribute isIgnoreRequest, thymeleaf will look for the methods getIsIgnoreRequest and setIsIgnoreRequest.
What happens is kotlin generates the getters and setters for isXXX booleans in a different way than the standard, and thymeleaf fails when calling them with the standard syntax. You can see more on how kotlin generates the getters and setters for booleans in
https://github.com/sockeqwe/fragmentargs/issues/46 or
https://github.com/sockeqwe/sqlbrite-dao/issues/27
As to solve your issue, the best solution is probably naming your attributes in a different way so that kotlin doesn't mess with the standard for generating getter and setter methods (which IMO only complicates things unnecessarily; although some frameworks like JSF had a similar issue with isXXX booleans since forever).
I'm writing a REST service using Spring Boot and JPA. I need to be able to validate some of the input fields and I want to ensure I'm using a proper pattern for doing so.
Let's assume I have the following model and I also have no control over the model:
{
"company" : "ACME"
"record_id" : "ACME-123"
"pin" : "12345"
"company_name" : ""
"record_type" : 0
"acl" : ['View','Modify']
"language" : "E"
}
The things I need to do are:
Ensure the value is not empty - This seems simple enough using the #NotEmpty annotation and I can pass a message.
Ensure the value is part of a valid list of values - The example here is the language property in the model above. I want the value to be either E,F or S. This seems possible using a custom annotation (eg #ValidValue({"E","F","S"})) but is there a better/"Springy" way to do this?
Ensure the values in a list are part of a valid list of values - The example here is the acl property. Again this seems possible with a custom annotation like #ValidListValues({"View", "Modify", "Delete", "Hide"}) but same question as above.
Set a default value - From what I read, custom validator annotations are only able to validate and not modify. I would like to do something like #DefaultValue(value=5) if the value is null. Is this possible? More on this below.
Set a default value to the return of a static method - For example if the pin field in model above isn't set, I want to set it to something like Util.getRandomDigitsAsString(5).
Use values from another property - I would like to validate that one property contains the string from another property. Using the example model, I want to ensure that record_id starts with company.
I have this setup in what I believe is a standard way with the controller -> service -> DTO -> DAO -> Model. Another option I was thinking about was creating a method in the validateCreate() that would go through all of the items above and throw an exception if needed.
Thanks.
Yes, NotEmpty is the right way
You should define a Language enum. The language field of your POJO should be of type Language
Same as 2. Define an Acl enum.
Define that in your Java code. Initialize the value of the field to 5 by default. If the JSON contains a value, Jackson will set the field value to the value in the JSON. Otherwise, it will stay as 5. Or initialize the field to null, and add a method getValueOrDefault(int defaultValue) that returns the default value you want if the value is null.
Same as 4
Define a custom validator that applies on the class itself, rather than a property of the class. In the validator chec that the two related values are correct.
I set a bean's property to a String object, then when I try to get the class name of the property ,below error is thrown out:
Expected hash. plist[0].javaType evaluated instead to freemarker.template.SimpleScalar on line 7, column 26 in ibatis/macro.ftl.
template code is as below:
<#assign clsName=plist[0].javaType.class.name>
When property javaType is set to a java bean, class name can be properly got. Why is it? I need the property could be given any type, java bean ,non java bean.
The root of the issue here is that FreeMarker doesn't work with Java values/objects directly. The template language has its own simple type-system, and stuff coming from outside is mapped to that through a technique called object-wrapping. (Values that doesn't come from outside doesn't even have a wrapped object inside.) That you was still able to get the class of some object is purely accidental... What happens is that the object-wrapping machinery decides that the object should be mapped to the "hash" FreeMarker type, and the hash items will correspond to the JavaBean properties of the objects. The object has a getClass() method, which is (mistakenly) seen as the getter of the "class" property.
So there's no universal way of getting the class... among others because sometimes there's no class to get. You could write a TemplateMethodModelEx that does a good enough effort to do so.
In a spring configuration, what is the difference between using name vs id? I'm aware that XML restricts the "id" attribute to be unique in a document and limits the characters for using in the id. But otherwise when declaring a bean, what is the difference between using the "name" attribute vs the "id" attribute?
Essentially, this is really just a XML matter. But you can also use the name attribute to specify aliases for a bean using characters which would be illegal in an id, I think.
In general, you should try to use id instead of name when you can. That way, the parser can catch duplicates for you.