Why freemarker not reading my Java object (POJO)? - freemarker

I am using freemarker to process html elements, inside the template file, it can read one of my legacy java object by giving ${form.fontStyle}, but it doesn't read my newly created java object"
public class SectionHeaderInfo implements Serializable {
private static final long serialVersionUID = 1L;
// the form object holds the setting of the form.
private Form form;
// the form section object
private FormSection section;
private String languageText;
public String name;
public SectionHeaderInfo(Form form, FormSection section, String languageText) {
this.form = form;
this.section = section;
this.languageText = languageText;
}
public void getName() {
return "whatever";
}
I added getName just for testing, but it complains
Caused by: freemarker.core.UnexpectedTypeException: For "." left-hand operand: Expected a hash, but this evaluated to a (wrapper: com.xxx.SectionHeaderInfo):
I compared the two java classes, tried implements TemplateModel, Serializable, nothing can get it work.
What am I missing here ?

Related

How to generate cache CustomKey for Redis in Spring Boot

I have spring boot application which is integrated with Redis cache. Have to implement caching for one of the method call. That method argument is an object with multiple params which is external Request object. This object params will vary for each request also based on that param and its values output of the method is varies. I need to create a cache key using that Request object field/param values. How to achieve it.
We can use SimpleKeyGenerator only when method params are static?
UserService.java
#Cacheable(value = "usercache", keyGenerator="customKeyGenerator")
public UserResponse getUserResp(User user){
//Some backend calls
return user
}
User.java
public class User {
private String firstname;
private String lastname;
private Integer age;
private Date dob;
private Address address;
// Another 10 params
}
In this method implementation User object is dynamic. I have to create a cache key based on User object fields which is having valid non null values. How to achieve it.
I have implemented as like below.
User.java
public class User implements Serializable {
private String firstname;
private String lastname;
private Integer age;
private Date dob;
private Address address;
// Another 10 params
#Override
public int hashCode() {
final int prime = 31;
//Add necessary fields
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
//Add necessary fields
}
}
public class UserKeyGenerator implements KeyGenerator{
private static final String UNDERSCORE_DELIMITER = "_";
#Override
public Object generate(Object target, Method method, Object... params) {
String cacheKey = null;
if(params.length > 0) {
StringJoiner paramStrJoiner = new StringJoiner(UNDERSCORE_DELIMITER);
User userReq = (User) params[0];
paramStrJoiner.add(target.getClass().getSimpleName());
paramStrJoiner.add(method.getName());
paramStrJoiner.add(String.valueOf(userReq.hashCode()));
cacheKey = paramStrJoiner.toString();
}
return cacheKey;
}

Spring/Jackson AutoMapping for field that can be multiple types

In my application, I am trying to get an OAuth token from multiple different providers.
According to the OAuth Spec, scopes should be sent as a string that contains a space delimited list of scopes.
However, I have noticed that some implementations return the scope as a List of strings.
In my application, I would like to store the scopes as a string that contains a space delimited list of scopes, as per the specification.
To do so, I created an Dto that looks as such (this dto is the same as the entity):
public class OAuthTokenDto {
// variables named to reflect OAuth Spec sends them to us
private String access_token;
private String refresh_token;
private Integer expires_in;
private String scope;
private String token_type;
public OAuthTokenDto() {
}
...
}
Is there a way to handle the fact that scopes might be sent as a List? In its current state, I am using rest template to do the mapping and it throws an exception because of this mismatch
You can make use of Jackson's #JsonAnyGetter and #JsonAnySetter. What you can do is, you can catch the unspecified tokens with this in which case your scope element and then typecast depending on the object type.
public class OAuthTokenDto {
// variables named to reflect OAuth Spec sends them to us
private String access_token;
private String refresh_token;
private Integer expires_in;
private String token_type;
#JsonIgnore
private Map<String, Object> properties = new HaspMap<String, Object>();
public OAuthTokenDto() {
}
#JsonAnyGetter
public Map<String, Object> getProperties() {
return this.properties;
}
#JsonAnySetter
public void setProperty(String name, Object value) {
this.properties.put(name, value);
}
}
And you can verify if your scope is an object or list of objects as follows
if(properites.get("scope") instanceof List<String>)
{
List<String> scopeList = properties.get("scope");
}
else
{
String scope = properties.get("scope");
}
Thanks to #Deadpool, the following implementation works
From jackson 2.6 you can use JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY
#JsonProperty("scope")
#JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private String[] scope;
Clean solution:
Create converter class:
class ScopeConverter extends StdConverter<List<String>, String> {
#Override
public String convert(List<String> scopes) {
return scopes.stream().collect(Collectors.joining(" "));
}
}
Use it for scope property:
#JsonDeserialize(converter = ScopeConverter.class)
public String scope;
Enable:
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
Now you can deserialize both cases scope being List and one element (with space separated scopes)

#value not able to read from application.properties in springboot

I am trying to read value from properties file using #value as follows.
#Value("${abc}")
private String abc;
public List<Record> fetchRecords(String label, String predicate) {
System.out.println(abc);
}
but value of abc is coming as null. Whereas when I try to print the same using #PostConstruct, I am getting the expected value.
#PostConstruct
public void postconstruct() {
System.out.println(abc);
}
Any lead why I am not able to get the value in fetchRecords() method?
For reference, here goes the code
#Component
public class AuditRecord {
private String subject;
private String predicate;
private String oldObject;
private String newObject;
private String readOnlyAuthInfo;
#Value("${registry.system.base}")
private String registrySystemContext;
public void record(DatabaseProvider provider) throws AuditFailedException {
System.out.println("---registrySystemContext value showing null here---"+registrySystemContext);
...
}
#PostConstruct
public void postconstruct() {
System.out.println("---registrySystemContext value showing here as expected---"+registrySystemContext);
}
}
The way I am calling is as follows:
#Component
public class RegistryDaoImpl implements RegistryDao {
...
private void addOrUpdateVertexAndEdge(Vertex v, Vertex dbVertex, GraphTraversalSource dbGraph, String methodOrigin){
...
AuditRecord record = new AuditRecord();
record
.subject(dbVertex.label())
.predicate(e.label())
.oldObject(null)
.newObject(existingV.label())
.record(databaseProvider);
}
}
P.S. registry.system.base is in application.yml.
You need to autowire AuditRecord and not use new directly. Only that way you will have your class in Spring's context.
We don't know your exact usage of the class but you might be interested in Spring's FactoryBean.

Make #ConfigurationProperties properties partially mandatory

Given the following simple (not nested) configuration properties class:
#ConfigurationProperties("env")
public class MyServiceProperties {
private String anyProperty;
private Boolean anyOther;
...
}
How can I make sure that anyProperty is mandatory, i.e. env.any-property must be set to startup the application? Is there any difference for nested configuration property classes?
You can perform all kind of validations.
#Validated
#ConfigurationProperties("env")
public class MyServiceProperties {
#NotNull
#Min(5)
private String anyProperty;
// this is for nested objects
#Valid
#NotNull
private FooNested fooNested;
public static class FooNested{
#NotNull
private String someVal;
}
}
You could also perform manual validation in setter
#Validated
#ConfigurationProperties("env")
public class MyServiceProperties {
private String anyProperty;
public void setAnyProperty(String anyProp){
// just an example
if(anyProp.lenght < 6){
throw new RuntimeException();
}
this.anyProperty = anyProp;
}
}

Spring data mongodb No mapping metadata found for java.lang.String error

I am trying to use spring data mongodb to retrieve a list of collections from the DB. However as soon as my code runs I get the following exception:
org.springframework.data.mapping.model.MappingException: No mapping metadata found for java.lang.String
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:209)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1008)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.access$100(MappingMongoConverter.java:75)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:957)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:924)
at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:78)
at org.springframework.data.mapping.model.SpELExpressionParameterValueProvider.getParameterValue(SpELExpressionParameterValueProvider.java:63)
at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:70)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:232)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:212)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:176)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:172)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:75)
I can't seem to find the solution for this anywhere. Any help would be highly appreciated
Here is my java code which is used to retrieve the data:
public List<GateAppointment> listGateAppointments() {
List<GateAppointment> gateAppointments = null;
try{
MongoOperations mongoOperation = (MongoOperations)getMongoTemplate();
gateAppointments = mongoOperation.findAll(GateAppointment.class,COLLECTION_NAME);
}
catch(Exception e){
e.printStackTrace();
}
return gateAppointments;
}
And public static final String COLLECTION_NAME = "gateVisitAppointments";
The following is a sample of my DB data(Sorry, cant post image directly as I dont have 10 rep):
Please click to view DB Image
Following is my GateAppointment class file properties (The rest of the file has all the setters and getters):
package com.ig.avs.common.entity.db;
public class GateAppointment {
/**
* The Class GateAppointment.
*
*/
private String gate;
private String gateAppointmentNbr;
private String bol;
private String containerNbr;
private String iso;
private String line;
private String transactionType;
private String truckingCompany;
private String truckId;
private String appoinmentDate;
private String apSlot;
private String slotStartTime;
private String slotEndTime;
private String isMapped;
private String status;

Resources