Accessing Object Property Directly thymeleaf - java

Let's say I have a class Factory with 2 fields: fName and fArea. Is it possible to refer to these fields through a single object f1 (an instance of Factory) added to either a Model or a ModelAndView? Resulting to something like this ${f.fArea} (where f is the String attributeName argument of addObject method).

Yes, that's possible. That syntax is the basis of how thymeleaf expressions work...
// Controller
#GetMapping("/whatever")
public String whatever(Map<String, Object> model) {
model.put("f", new Factory());
return "whatever";
}
// Template
</span th:text="${f.fArea}" />
http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#variables

Related

Map null values to default using builder with MapStruct

I want to map field from Source to Target class, and if the source value is null, I would like to convert it to default value based on the data type ("" for strings, 0 for numeric types etc.). For setting the values, I am not using regular setters, but builder (with protobuf, so the names of the methods is newBuilder() and build()).
class Source {
private final String value; // getter
}
class Target {
private final String value;
public static Builder newBuilder() {return new Builder()}
public static class Builder {
public static setValue() {/*Set the field*/}
public static Target build() {/*Return the constructed instance*/}
}
My mapper looks like this:
#Mapper(
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT,
nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT
)
public interface TargetMapper {
Target map(Source source);
}
The generated mapper implementation with this code calls target.setValue(source.getValue()), instead of performing the null check and setting default value if source returns null. The interesting part is when I add the following annotation to the map method, the null check is present in the implementation.
#Mapping(source="value", target="value", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
Is this a bug in MapStruct with builders, or am I missing some configuration to be ably to set the null mapping as a default policy, instead of duplicating it on all field mappings?
EDIT: For some reason, adding nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS to the class level #Mapper annotation adds the null check, but does not explicitly set the value, just skips the call to setValue. For protobuf, this is okay, since this functionality is in the library, but for other implementations the field would remain null.
#Mapping(source="value", target="value", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
applies to update method (so methods that have the #MappingTarget annotated parameter
There's no real counterpart for regular methods:
1. NullValueMappingStragegy applies to the bean argument itself.
2. NullValueCheckStragegy does perform a check on bean properties, but does not return a default.
Naming is not really brilliant and it has a long history. We still have the intention to align this one day.
A solution would be to use an Object factory creating the builder target object and pre-populate it with default values and then let MapStuct override these one day.
Perhaps you could do something like this:
#Mapper(
// to perform a null check
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS
)
public interface TargetMapper {
Target map(Source source);
}
// to create a pre-defined object (defaults set a-priori). Not sure
// whether this works with builders.. just try
#ObjectFactory
default Target.Builder create() {
Target.Builder builder = Target.newBuilder();
builder.setValueX( "someDefaultValue" );
return builder;
}

Reading values assigned to annotated field

i am very new to JAVA 8 and SPRING MVC . I have a java bean which is a POJO with setter and getter. My Spring web service using reflection maps the request parameters to the POJO.
I want to do input validation using annotation. I have a requirement were i need to read all the values of the annotated field and check atleast one value is provided. I wrote a sample code.... BUT NOT SURE HOW TO GET THE VALUES THAT ARE ASSIGNED TO A FIELD. Please do share sample code if you have:
public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
boolean canProceed = false;
for(Field field : DocumentSearchRequest_global.class.getDeclaredFields())
{
if (field.isAnnotationPresent(ValidDocumentModifiedDate.class))
{
String name = field.getName();
//IAM ABLE TO GET THE NAME OF THE FIELD
System.out.println("1.name : "+ name);
System.out.println("2. "+field.getType().getName());
}
}
// Method[] method = DocumentSearchRequest_global.class.getDeclaredMethods();
for (Method method :DocumentSearchRequest_global.class.getDeclaredMethods() )
{
System.out.println(method.getName() );
//ABLE TO GET NAME OF THE GETTER AND SETTER METHODS IN THE POJO
//CAN U SUGGEST HOW TO READ THE VALUE OF A PARTICULAR FIELD.. EITHER BY //GETTING THE VALUE FROM THE GET METHOD??? ...
}
You can get the values by calling method.invoke(Object, Object...) where first parameter is your class instance on which method is to be executed and second variable arguments are arguments of the method. In your case it'll be null or empty. Here is simple code snippet Object value = method.invoke(DocumentSearchRequest_global_instance);

How to explain usages of square brackets ([]) operator in EL expressions

When I read Spring PetClinic sample application, I found they always put the add and modify functionalities into a single JSP file, and they use ${owner['new']} expression to customize elements on current page, for example "New Owner" or "Owner" for a label.
Are there any other usages of [] operator in JSP (Spring) environment?
The Controller file has the following snippet:
#RequestMapping(value = "/owners/new", method = RequestMethod.GET)
public String initCreationForm(Map<String, Object> model) {
Owner owner = new Owner();
model.put("owner", owner);
return "owners/createOrUpdateOwnerForm";
}
#RequestMapping(value = "/owners/{ownerId}/edit", method = RequestMethod.GET)
public String initUpdateOwnerForm(#PathVariable("ownerId") int ownerId, Model model) {
Owner owner = this.clinicService.findOwnerById(ownerId);
model.addAttribute(owner);
return "owners/createOrUpdateOwnerForm";
}
The JSP file has the following snippet:
<h2>
<c:if test="${owner['new']}">New </c:if> Owner
</h2>
The [] will allow you to:
Get a property, if the object is a bean (has getters and setters):
${car['type']}
This will be equivalent to car.getType(); (or car.isType() if the type field is a boolean).
Get a key's value, if the object is a Map:
${carMap['Volvo']}
This will be equivalent to carMap.get('Volvo'); when carMap is a Map.
Get an index, if the object is an array or List:
${cars[1]}
This is equivalent to cars[1] if cars is an array or equivalent to cars.get(1) if cars is a List.
More details/source: http://docs.oracle.com/javaee/6/tutorial/doc/bnahu.html
Edit:
Your question's expression (${owner['new']}) falls into the first case. In the petclinick app, the Owner class is a subclass of Person which is a subclass of BaseEntity. And BaseEntity has a method isNew() (so Owner has that method as well).
This way the snippet ${owner['new']} is equivalent to owner.isNew().
Consider following code
bikesMap.put("honda","cbr250r");
bikesMap.put("yamaha","yzfr15");
request.setAttribute("bikesMap",bikesMap);
request.setAttribute("company","honda");
So if we write ${bikesMap["company"] then it will not evaluate to "cbr250r" because what we are providing in [] is a string literal so container will try to find a key "company" which is not present. But if we write ${bikesMap[company]} then this EL will evaulate to "cbr250r".
${bikesMap[compapny]} will evaulate to "cbr250r" because there is a request attribute named company and the value of company i.e. "honda" is a key to the bikesMap.
${bikesMap["company"]} will not evaluate to "cbr250r" because there is no key named "company".
An advantage of [] operator over dot operator is that it can access lists and arrays effectively. You can write ${bikesList["1"]} but you can't write ${bikesList.1}.
Hope this helps

Java - Reflection. Set value for the class object which are dynamically created

Hi have a class[many] for which I create object dynamically during run time. now I want to set value for the fields which are private fields. How do I set them.
I have seen many examples which explain this but we need to know the field name and only than the values can be set.
for my case I have some set of default values for set of primitive and non primitive types and find the field type during run time and set the default values for them.
For example:
LoginBean loginBean = new LoginBean();
Method setUserName = loginBean.getClass().getMethod("setUserName", new Class[]{String.class});
setUserName.invoke(loginBean, "myLogin");
My case is different and i don't even know the field name but have to set the default value according to field type.
how to do this using reflection or even better in spring.
You can say yourBean.class.getFields(); which will give array of Field.
Using Field you can find its name and type, and do the desired work (setting some value, if its type is == some primitive type)
This example sets default values on several fields within a class using reflection. The fields have private access, which is toggled on and off via reflection. Field.set() is used to set the values of the field on a particular instance instead of using the setter method.
import java.lang.reflect.Field;
import java.util.Date;
public class StackExample {
private Integer field1 = 3;
private String field2 = "Something";
private Date field3;
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
StackExample se = new StackExample();
Field[] fields = se.getClass().getDeclaredFields();
for(Field f:fields){
if(!f.isAccessible()){
f.setAccessible(true);
Class<?> type = f.getType();
if(type.equals(Integer.class)){
f.set(se, 100); //Set Default value
}else if(type.equals(String.class)){
f.set(se, "Default");
}else if (type.equals(Date.class)){
f.set(se, new Date());
}
f.setAccessible(false);
}
System.out.println(f.get(se)); //print fields with reflection
}
}
}
1) By Using Spring Constructor/Setter Injection. You dont need to know the attribute name , just type will do. Like as following:
<bean id="myBean" class="myBean">
<constructor-arg type="int"><value>1</value></constructor-arg>
</bean>

Jasper Reports: How does one call a java method with a int parameter from a JasperDesign class

I've used jasper without using xml (I must change this still) but I have an implementation of a JasperDesign that i make use of ... I create a JRDesignTextField with a JRDesignExpression,
I would like to setup the expression so that I can get jasper to call a method on each element within a JRBeanCollectionDataSource with a integer parameter... currently i can only call methods that returns a value and take in no arguments. The expression for this is shown below:
final JRDesignExpression exp = new JRDesignExpression();
exp.setValueClass(String.class);
exp.setValueClassName(String.class.getName());
exp.addFieldChunk("column0");
You should consider using a different data-source, other than JRBeanCollectionDataSource. The JRBeanCollectionDataSource calls getter methods for each field, which is what you want to avoid.
You can use JRMapCollectionDataSource, which is created from a collection of maps. You can call the keys of your maps as you wish, like 'column0', 'column1' (or simply '0', '1', etc.)
Another option is to directly implement the JRDataSource interface, where you can implement the getFieldValue() whichever way you like.
You can use setText instead of adding chunks yourself. Jasper will parse the text, adding chunks as needed - $P{param} for parameters, $F{field} for fields, $V{var} for variable, etc. For example:
exp.setText( "$F{column0}.myMethod($V{someIntVar})" )
Try this:
final DRIExpression<Boolean> hasZeroPvMeasure = boolExp("$F{" + PROP_THIS + "}.hasZeroPvMeasure($P{controllingModel})");
cols.add(flagCol(hasZeroPvMeasure, "0-PV"));
Where your data object needs:
public static final String PROP_THIS = "this";
/**
* Used in Jasper Expressions
* #return
*/
public ControllingRowData getThis() {
return this;
}
Jasper Dynamic Reports also has an implementation to interpret _THIS but due to a bug it fails during validation before it gets executed ...
See in JRAbstractBeanDataSource:
public static final String CURRENT_BEAN_MAPPING = "_THIS";
And JRAbstractBeanDataSource:
protected static boolean isCurrentBeanMapping(String propertyName)
{
return CURRENT_BEAN_MAPPING.equals(propertyName);
}
/*...*/
if (isCurrentBeanMapping(propertyName))
{
value = bean;
}
/*...*/

Categories

Resources