How to get class name of String object? - freemarker

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.

Related

No Creators Exist: Cannot Deserialize

I got an error ...(no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) which indicates that I need a property-based creator. I have a few constructors with different parameters, but no default.
My solution was to add a default constructor SomeClass() {}. My question is: why does this happen? Also, what is a delegate/property-based constructor?
If there is no constructors that is annotated with #JsonCreator, by default, Jackson needs a default no-args constructor in order to parse the JSON into POJO or bean classes. That is why when you add a default constructor, it will work fine.
And if you don't actually need the usage of the default constructor, just add it for Jackson only, you can set it to private, protected or package-protected. Jackson is still able to fill all the fields via reflection.
Regarding the no delegate- or property-based Creator, they are constructors that is annotated with #JsonCreator. In Jackson, there are 2 types of Creator/JsonCreator which are delegate-based Creator and property-based Creator.
Delegate-based creators take just one argument, which is NOT annotated with #JsonProperty. Type of that property is used by Jackson to bind the whole JSON value (JSON Object, array or scalar value), to be passed as value of that one argument.
Property-based creators take one or more arguments; all of which MUST be annotated with #JsonProperty, to specify JSON name used for property. They can only be used to bind data from JSON Objects; and each parameter represents one property of the JSON Object; type of property being used for binding data to be passed as that parameter when calling creator.
You can read for more details about these 2 creators in the article below.
http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html

Are Thymeleaf model attributes not allowed to start with 'is'?

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).

Faker for Grails gives variable not defined error

I have a Grails 2.4.4 application configured with spring-security-core. I want to generate fake users in the BootStrap using the faker plugin. However when I instantiate the bean fakerService in BootStrap and try using it ie. fakerService.firstname(), I get an error :
ERROR context.GrailsContextLoaderListener - Error initializing the application: Cannot invoke method firstName() on null object
Message: Cannot invoke method firstName() on null object
I'm just a beginner in Grails. Am I doing the Dependency Injection wrong?
http://pasteboard.co/rvbihRU.png
Yes you are :)
A little background. When you add a class-scope variable (a field) in a Groovy class without an explicit scope modifier (e.g. public, private, protected) it defaults to public just like classes and methods. But it is considered a property in the JavaBean sense, so the Groovy compiler creates a getter and a setter for you based on the name. So if you declare def foo and String bar (it doesn't matter whether you specify the type) you'll get Object getFoo(), void setFoo(Object), String getBar(), and void setBar(String) methods (you should decompile a POGO class with a decompiler and see this for yourself - it's pretty cool stuff - I recommend JD-GUI, but use whatever you prefer). If you had declared any of them already Groovy would skip that one and not overwrite yours. This is cool because you can treat the variable like a simple public field, but at any time add getter and/or setter logic and not affect calling clients (Groovy or Java, since the Java classes would have been calling the getter and setter all along, and Groovy calls the getter and setter for you when you read or write a property).
So why am I babbling on about this? Dependency injection is done by Spring - you're injecting Spring beans. There are various ways to do this, but the default in Grails is to use autoinject-by-name. So for any bean registered in the ApplicationContext and special classes like BootStrap, integration tests, etc., Spring scans the methods looking for setters. It strips off "set" and lowercases the next letter, and that's the "property" name of the setter. If there's a bean with that name in the ApplicationContext, Spring will call that setter, passing the bean with that name, and if the types are in sync, your class will have a reference to that bean.
You added a local variable. Nothing special happens to local variables, and Spring doesn't see them, and they're not candidates for dependency injection. Move the declaration to class scope, before the init closure, e.g.
class BootStrap {
def fakerService
def init = {
...
}
}
and the Groovy compiler will add a getFakerService method that isn't of much interest, but also a setFakerService method that Spring will see. It will determine that its property name is "fakerService", see that there is a bean with that name, and call the setter. This all happens before Grails calls the init closure, so at that point the value will be a non-null FakerService eagerly awaiting your calls.

Spring Expression Language (SpEL) for Array Method Parameters

I have a Spring Integration project where I am trying to call a method on a bean that takes a String object and Class object as parameters. The class object I want to pass to it is Long[].class but I can't figure out the correct syntax. I've tried various combinations of the following to no avail:
expression="#parser.readValue(payload, T(java.lang.Long[]))"
For now I've simply wrapped the call in another java class (hardcoding the Class type) and call that via SpEL. What is the correct syntax for an array class parameter?
This works...
...(payload, new java.lang.Long[0].class)

Representation of nulls in Freemarker with Spring Framework

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"}

Resources