I have a simple class:
public class MyClass {
public final static long MAIN = 1;
#Setter #Getter
protected int id;
}
(#Setter #Getter are lombok annotations for Setter and Getter methods.)
In Freemarker template I would like to create a condition like:
<#if myClassInstance.id == myClassInstance.MAIN>
But the right hand side of the if expression is according to FreeMarker undefined. Is there a way to do this? Thanks!
The template language is not aware of Java classes. But you can expose static members through the data-model (template context). See: http://freemarker.org/docs/pgui_misc_beanwrapper.html#autoid_55
I know that this question already have an accepted answer but I am still writing piece of code that can be help full for some one else.
Use below piece of code in java
BeansWrapper w = new BeansWrapper();
TemplateModel statics = w.getStaticModels();
map.put("statics", statics); // map is java.util.Map
template.process(map, out); // template is freemarker.template.Template
Then access constant in ftl
${statics["com.model.to.gen.Common"].FLAG_YES}
here com.model.to.gen.Common is a class and FLAG_YES is a static constant.
You can use expose fields option. So you can use data models without accessors (getters/setters).
BeansWrapperBuilder wrapperBuilder = new BeansWrapperBuilder(Configuration.VERSION_2_3_23);
wrapperBuilder.setExposeFields(true);
Template template = freemarkerConfiguration.getTemplate("mytemplatefile.ftl");
StringWriter stringWriter = new StringWriter();
template.process(model, stringWriter, wrapperBuilder.build());
System.out.println(stringWriter.toString());
I have another similar but effective way.
First, we can create a util class like this:
/**
* FreeMarker Utils.
*
* #author Eric Chan
*/
public abstract class FreeMarkerUtils {
/**
* init for static classes and fields.
*
* #param model model
*/
public static void initStatics(final Model model) {
// you can also create the Version like: new Version("2.3.27");
BeansWrapper wrapper = new BeansWrapper(new Version(2, 3, 27));
TemplateModel statics = wrapper.getStaticModels();
model.addAttribute("statics", statics);
}
}
And next, invoke it in your Controller:
FreeMarkerUtils.initStatics(model);
That's all, now you can access static variables in your .ftl like this:
${statics["com.springboot.constants.TestConstants"].NAME}
Related
I Have a property file sqlqueries.properties.
I want an abstract class to be generated during the build/packaging in spring boot application.
sqlqueries.properties
SELECT_QUERY=SELECT * from EMPLOYEE
SqlQueries.java
public abstract class SqlQueries {
public static final String SELECT_QUERY;
static {
SELECT_QUERY="SELECT * from EMPLOYEE";
}
}
I came across the similar implementation in one of the source code with the comment
/** Generated by maven-utils-plugin:convertProperties */
Am not able to figure it out , how to do the same kind for my project
I have a REST API built with Spring Boot / Spring MVC, using the implicit JSON serialization via Jackson.
Now, just before the implicit serialization, I would like to "inject" some UI texts from message resources into the objects that Jackson converts into JSON. Is there some neat, simple way to do this?
As a much simplified example, below I'd like to set Section title to a user-visible value, based purely based on its SectionType.
(Sure, I could hardcode the UI texts in SectionType, but I'd rather keep them separate, in resource files, because it's cleaner, and they might be localised at some point. And I can't autowire MessageSource in the entities / model objects which are not Spring-managed.)
#Entity
public class Entry {
// persistent fields omitted
#JsonProperty
public List<Sections> getSections() {
// Sections created on-the-fly, based on persistent data
}
}
public class Section {
public SectionType type;
public String title; // user-readable text whose value only depends on type
}
public enum SectionType {
MAIN,
FOO,
BAR;
public String getUiTextKey() {
return String.format("section.%s", name());
}
}
Somewhere in a #RestController:
#RequestMapping(value = "/entry/{id}", method = RequestMethod.GET)
public Entry entry(#PathVariable("id") Long id) {
return service.findEntry(id);
}
UI texts that I'd like to keep separate from code (messages_en.properties):
section.MAIN=Main Section
section.FOO=Proper UI text for the FOO section
section.BAR=This might get localised one day, you know
And what I'd like to do in a Spring-managed service/bean somewhere (using Messages, a very simple helper wrapping a MessageSource):
section.title = messages.get(section.type.getUiTextKey())
Note that if I call entry.getSections() and set the title for each, it will not affect the JSON output, since the Sections are generated on the fly in getSections().
Do I have to go all the way to custom deseriazation, or is there a simpler way to hook into the model objects just before they get serialized by Jackson?
Sorry if the question is unclear; I can try to clarify if needed.
As I said in the comment you can write an Aspect around every controller method that returns Section.
I wrote a simple example. You have to modify it with the message source.
Controller:
#RestController
#RequestMapping("/home")
public class HomeController {
#RequestMapping("/index")
public Person index(){
Person person = new Person();
person.setName("evgeni");
return person;
}
}
Aspect
#Aspect
#Component
public class MyAspect {
#Around("execution(public Person com.example..*Controller.*(..))")//you can play with the pointcut here
public Object addSectionMessage(ProceedingJoinPoint pjp) throws Throwable {
Object retVal = pjp.proceed();
Person p = (Person) retVal; // here cast to your class(Section) instead of Person
p.setAge(26);//modify the object as you wish and return it
return p;
}
}
Since the aspect is also a #Component you can #Autowire in it.
Hey this is a very simple question. Can I call a variable, in this case an array, from a void method? I have declared my arrays at the class level and initialized them in a void method. Not sure it I am doing this correctly but I am trying to call the array from another class. I am a beginner. Thank you for the help.
ex:
public class HeyThere{
public double me[];
public void yeahYou(int you){
me = new me[69]
}
}
Here you declarate a public variable (array)
public double me[ ];
and here you instantiate it in a method
me = new me[69]
Yes, since your class level array me is scoped as Public, you will be able to access it from another class after you instantiate the HeyThere class.
Ex:
public class HeyThereCaller
{
..
....
public void SomeMethod()
{
...
....
HeyThere heyThereInstance = new HeyThere();
double[] meArray = heyThereInstance.me;
}
}
HeyThere obj1; double a = obj1.me[0]; This is going to give an error in Java though, because me is not instantiated
Yes, you certainly can! Because me is public, you can access it from outside of the class in which it is stored.
Also, you spoke of accessing it from a void method. The return type of a method has no effect on the data it can access; void only means that the method doesn't return a value when called.
If you want to study how variables can be accessed in Java, there is some useful info on this page.
I have to consume a REST api which follows a common syntax across all retrievable objects:
baseUrl + domainObjectName + qualifier
E.g.
"http://myweb.com/api/" + "cities" + "/{id}"
I created a BaseDao for my data layer and I would like to set up in DAO instantiation the base url for each domain object (baseUrl + domainObjectName). The problem is I have my api Base url defined in the properties file (and would like to keep it that way), and it is not available in the DAO constructor.
This is what I have:
public abstract class BaseDao {
protected static final String ID_QUALIFIER = "/{id}";
protected String domainObjectName = "";
protected String doBaseUrl = "";
#Value("#{config['baseUrlRest']}")
public String apiBaseUrl;
public GenericDaoRestImpl(String domainObjectName) {
this.domainObjectName = domainObjectName;
this.doBaseUrl = apiBaseUrl + domainObjectName;
}
}
When my dao is instantiated, apiBaseUrl is still null, although after creation it is indeed injecting the baseUrl property.
Is there any way around this, like injecting the property as a static constant?
This happens because Java doesn't allow to set fields of a class before the constructor is called. So Spring can't inject the value. There are two solutions:
Pass the value to the constructor instead (example 1)
Use #PostConstruct (example 2)
Example 1:
public GenericDaoRestImpl(
#Value("#{config['baseUrlRest']}") String apiBaseUrl
String domainObjectName
) {
...
}
Example 2:
#Value("#{config['baseUrlRest']}")
public String apiBaseUrl;
public GenericDaoRestImpl(String domainObjectName) {
this.domainObjectName = domainObjectName;
}
#PostConstruct
public void init() {
this.domainObjectName = domainObjectName;
this.doBaseUrl = apiBaseUrl + domainObjectName;
}
I prefer the #PostConstruct because constructor injection eventually leads to constructors with many parameters which makes them unwieldy.
If you don't like it, your third option is using the builder pattern with a fluent interface.
With this class
#Component
public class Sample {
#Value("${my.name}")
public static String name;
}
If I try Sample.name, it is always 'null'. So I tried this.
public class Sample {
public static String name;
#PostConstruct
public void init(){
name = privateName;
}
#Value("${my.name}")
private String privateName;
public String getPrivateName() {
return privateName;
}
public void setPrivateName(String privateName) {
this.privateName = privateName;
}
}
This code works. Sample.name is set properly. Is this good way or not? If not, is there something more good way? And how to do it?
First of all, public static non-final fields are evil. Spring does not allow injecting to such fields for a reason.
Your workaround is valid, you don't even need getter/setter, private field is enough. On the other hand try this:
#Value("${my.name}")
public void setPrivateName(String privateName) {
Sample.name = privateName;
}
(works with #Autowired/#Resource). But to give you some constructive advice: Create a second class with private field and getter instead of public static field.
Soruce of this info is this: https://www.baeldung.com/spring-inject-static-field
Spring uses dependency injection to populate the specific value when it finds the #Value annotation. However, instead of handing the value to the instance variable, it's handed to the implicit setter instead. This setter then handles the population of our NAME_STATIC value.
#RestController
//or if you want to declare some specific use of the properties file then use
//#Configuration
//#PropertySource({"classpath:application-${youeEnvironment}.properties"})
public class PropertyController {
#Value("${name}")//not necessary
private String name;//not necessary
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
}
This is my sample code for load static variable
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class OnelinkConfig {
public static int MODULE_CODE;
public static int DEFAULT_PAGE;
public static int DEFAULT_SIZE;
#Autowired
public void loadOnelinkConfig(#Value("${onelink.config.exception.module.code}") int code,
#Value("${onelink.config.default.page}") int page, #Value("${onelink.config.default.size}") int size) {
MODULE_CODE = code;
DEFAULT_PAGE = page;
DEFAULT_SIZE = size;
}
}
For those who want to use ApplicationContext in the main class of a Spring Boot application, you can just use the return value of SpringApplication.run.
Although workarounds may need to be implemented, one should try to avoid them in most scenarios if possible. Spring is great at handling dependency injection and treats most objects as Singletons. This means that Spring can handle the creation of objects for you, and the injection of these objects at runtime. When combining this with the fact that your Spring managed bean is likely a Singleton, the use of static methods and variables is largely unnecessary. You can simply autowire in an instance of the object you are looking for at the constructor level or variable level and reference the non-static version of the method or variable. This is ideal and behaves similarly to a static reference. Non static variables are basically static because you are only ever using one instance of the object in every part of the code and because of dependency injection you are never handling the instantiation of the object, just like with a static reference! Great! Now I'm sure there are instances where you need the work around (i.e. you aren't using dependency injection or class is not a singleton), but try to not use workarounds if possible. Also this is just my 2 cents. Someone may be able to offer 3. (:
public class InjectableClass{
#Value("${my.value}")
private String myString;
public String nonStaticMethod(){
return myString;
}
}
public class LogicClass{
private InjectableClass injectableClass;
#Autowire
public LogicClass(InjectableClass injectableClass){
this.injectableClass = injectableClass;
}
public void logicClassMethod(){
System.out.println("Hey! Here is the value I set on myString: " +
injectableClass.nonStaticMethod() + ". That was
basically like using a static method!");
}
}