Setting freemarker template from classpath - freemarker

I have a web application that I need to manually obtain a Freemarker template - the template is obtained via a class in a library project, but the actual tpl file is contained in the web application classpath. So, there are 2 projects, one 'taac-backend-api' and another 'taac-web'; taac-backend-api has the code to grab the template, and process it, but taac-web is where the template is stores (specifically in: WEB-INF/classes/email/vendor.tpl) - I have tried everything from using springs classpath resource to using Freemarkers setClassForTemplateLoading method. I assume this would work:
freemarkerConfiguration = new Configuration();
freemarkerConfiguration.setClassForTemplateLoading(this.getClass(), "");
Template freemarkerTemplate = freemarkerConfiguration.getTemplate("/email/vendor.tpl");
yet, I always get a FileNotFoundException. Can someone explain the best way to obtain a template from the classpath?
Thanks.

this is what ended up working for me:
freemarkerConfiguration = new Configuration(Configuration.VERSION_2_3_28);
freemarkerConfiguration.setClassForTemplateLoading(this.getClass(), "/");
Template freemarkerTemplate = freemarkerConfiguration.getTemplate("email/vendor.tpl");

In 2017, the following is deprecated:
Configuration conf = new Configuration();
We should pass freemarker.template.Version to the constructor:
Configuration conf = new Configuration(new Version(2, 3, 23));
conf.setClassForTemplateLoading(Application.class, "/views");
where the version numbers refer to the current version of FreeMarker.
The views directory is located in src/main/resources.

freemarkerConfiguration = new Configuration();
freemarkerConfiguration.setClassForTemplateLoading(this.getClass(), "");
Template freemarkerTemplate = freemarkerConfiguration.getTemplate("template.tpl");
Use this method to load the classes from the package where your class is located, so if your class is
org.foo.SomeClass the templates will be looked for in /org/foo in the classpath. This keeps your templates stored with the class that uses/loads them.

If you are using Struts 2 and the Conventions plugin, wuntee's solution doesn't seem to work: setClassForTemplateLoading in turn creates an instance of ClassTemplateLoader which doesn't find files in jars no matter what path prefix is specified.
Instead, create an instance of StrutsClassTemplateLoader. (I do this in a custom sub-class of FreemarkerManager in its getTemplateLoader method.) It takes no parameters, so presumably it just knows how Struts and Conventions do things.

Use the following config and place it in application properties.
spring.freemarker.template-loader-path=

Related

Spring Boot application to have separated multiple property files

Coming from Play Framework, a handy feature that has helped to organize the application configurations was to use includes (Link) to spilt the various configurations into multiple .conf files as below.
application.conf Content
include "play-http.conf"
include "play-modules.conf"
include "play-i18n.conf"
include "authentication.conf"
include "hbase.conf"
include "custom-caches.conf"
include "custom-filters.conf"
#Any other root level application configurations
Is there an equivalent to this in Spring Boot .properties files?
From Spring 2.4, we can create multiple properties file for each profiles as below.
application-main1.properties
application-sub1.properties
application-sub2.properties
And then in default application.properties file we can group all sub profiles and activate the main profile
spring.profiles.group.main1=sub1,sub2
spring.profiles.active=main1
I am not sure if we can group sub profiles under default profile. You can try out
spring.profiles.group.default=sub1,sub2
This way you don't need to have another file for main profile.
I use yaml configuration files myself but I think that the configuration is mostly similar. You should take a look at the PropertySourcesPlaceholderConfigurer.
I have defined a PropertySourcesPlaceholderConfigurer bean to use a configuration override file located outside of the jar. Anything that is in the override file will be used instead of the default configuration. Anything that is not in the override file is still retrieved from the default configuration file. I think you can create a similar bean to achieve what you are looking for.
Here's my code:
#Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
var properties = new PropertySourcesPlaceholderConfigurer();
properties.setLocation(new FileSystemResource("./application.yaml"));
properties.setIgnoreResourceNotFound(true);
return properties;
}
For my use case, I only needed to define one properties location, but it is also possible to specify multiple locations:
...
properties.setLocations(Resource... locations);
...
My requirement was simply achieved using the spring.config.import (Link).
I created multiple property files such as hbase.properties, custom-caches.properties etc. And then in my application.properties imported those additional property files as below.
spring.config.import=hbase.properties,custom-caches.properties
#Any other properties in the application.properties file
Thanks

spring boot app cannot load bundle properties files

I am building an app that mostly provide REST services, nothing fancy. since my data consumed by the app can have multiple languages I thought about using the bundle files.
I created 3 files, one with the default file name and another two with specific languages. The files created using intellij IDE I am using.
I followed this guide https://www.baeldung.com/java-resourcebundle however on each run I am getting:
MissingResourceException: Can't find bundle for base name tp_app_strings, locale en_US
I tried numerous articles but none of them seems to resolve the issue.
One fun fact is that if I am using the #Value("classpath:tp_app_strings.properties") on a 'Resource' field I am able to get a reference to that file, so it spring is able to find it.
Additional thing that I tried was to create a WEB-INF directory and place the files there (read it in some article) but still no positive affect
The project structure is quite straight forward:
Spring boot version 2.2 running tomcat.
Any suggeestions would be highly appriciated
You can load the .properties file to the application context using #PropertySource annotation instead using #Value to load the .properties file to a org.springframework.core.io.Resource instance.
The usage;
#Configuration
#PropertySource("classpath:tp_app_strings.properties")
public class DefaultProperties {
#Value("${property1.name}") // Access properties in the above file here using SpringEL.
private String prop1;
#Value("${property2.name}")
private String prop2;
}
You wouldn't need java.util.ResourceBundle access properties this way. Use different or same class to load other .properties files as well.
Update 1:
In order to have the functionality of java.util.ResourceBundle, you can't just use org.springframework.core.io.Resource class. This class or non of it sub-classes don't provide functions to access properties by its name java.util.ResourceBundle whatsoever.
However, if you want a functionality like java.util.ResourceBundle, you could implement something custom like this using org.springframework.core.io.Resource;
#Configuration
public class PropertyConfig {
#Value("classpath:tp_app_strings.properties")
private Resource defaultProperties;
#Bean("default-lang")
public java.util.Properties getDefaultProperties() throws IOException {
Properties props = new Properties();
props.load(defaultProperties.getInputStream());
return props;
}
}
Make sure to follow correct naming convention when define the property file as java.util.Properties#load(InputStream) expect that.
Now you can #Autowire and use this java.util.Properties bean wherever you want just like with java.util.ResourceBundle using java.util.Properties#getProperty(String) or its overloaded counterpart.
I think it's problem of you properties file naming convention. use underline "_" for specifying locale of file like
filename_[languageCode]_[regionCode]
[languageCode] and [regionCode] are two letters standard code that [regionCode] section is optional
about code abbrivation standard take a look on this question
in your case change file name to tp_app_strings_en_US.properties

swagger codegen add #JacksonXmlElementWrapper(useWrapping = false) annotation to a single field

I'm currently using swagger codegen using yml to generate my models However I have one field, that is a List<Object> that needs to have the #JacksonXmlElementWrapper(useWrapping = false). I can see the #JacksonXmlElementWrapper in POJO.mustache but not in model.mustache. Does anyone know what to add in the yaml file or anywhere else so that field gets generated with that annotation? Thanks. I'm using spring-java language with gradle. I need this to be generated during build. so minimal changes are preferred.
According to the readme on their git, Swagger Codegen mention ways to do this:
https://github.com/swagger-api/swagger-codegen/blob/master/README.md
since you're using gradle:
We can use a custom template for the code generation as follows:
// build.gradle
swaggerSources {
inputFile = file('{name of your file}.yaml')
xyz {
language = 'spring'
// template directory path
templateDir = file('templates/{name of your custom directory}')
}
}
inside templates/{name of your custom directory}, you can store your custom mustache files, as in your case, all you have to do is download the required spring templates from git (e.g. this link is for pojo.mustache)
and add in the required changes to the template, along with the project and libraries folder. Run gradle build and it should generate.
There is a much simpler workaround however, where you can just use your own pojo class and add this in your existing config.json and remove the earlier entry for that model in your yaml file (of course):
"importMappings" : {
"{replace with className}": "{replace with packageName}.{replace with className}"
}
Hope this helps.

How to maintain, update application properties dynamically in Spring? [duplicate]

This question already has answers here:
How can I reload properties file in Spring 4 using annotations?
(3 answers)
Closed 6 years ago.
I would like to maintain a list of application properties like service endpoints, application variables, etc. in a Spring application. These properties should be able to updated dynamically (possibly through an web page by system administrator).
Does spring has an inbuilt feature to accomplish this requirement?
I am not sure spring has an implementation for updating the properties file dynamically.
You can do something like reading the properties file using FileInputStream into a Properties object. Then you will be able to update the properties. Later you can write back the properties to the same file using the FileOutputStream.
// reading the existing properties
FileInputStream in = new FileInputStream("propertiesFile");
Properties props = new Properties();
props.load(in);
in.close();
// writing back the properties after updation
FileOutputStream out = new FileOutputStream("propertiesFile");
props.setProperty("property", "value");
props.store(out, null);
out.close();
Externalizing properties, take a look here
Spring loads these properties which can be configured at runtime and accessed in your application in different ways.
Add your own implementation of a PropertySource to your Environment.
Warning: Properties used by #ConfigurationProperties and #Value annotations are only read once on application startup, so changing the actual property values at runtime will have no effect (until restarted).
I am not sure, but check if you can make use #ConfigurationProperties of Spring boot framework.
#ConfigurationProperties(locations = "classpath:application.properties", ignoreUnknownFields = false, prefix = "spring.datasource")
You can keep this application.properties file in you classpath
Change the properties in this file without redeploying the application
Java Experts - I am just trying to explore my view. Corrections are always welcome.
Edit - I read a good examples on #PropertySource here

OSGi bundle config without managed service or factory

Neil Bartlett's article http://njbartlett.name/2010/07/19/factory-components-in-ds.html shows the way to set config for bundles without using managed service or managed factory.
Search for examples of actually setting the config for this method either point to felix file install or to examples using managed service.
In answer to the question OSGi Declarative Services vs. ManagedService for configuring service? Neil Bartlett states "Note that DS never actually creates a ManagedService or ManagedServiceFactory for your component. It works by listening to Config Admin with a ConfigurationListener. However the internal details are unimportant... simply create configs with PID/factoryPID matching the component.name and it "just works"
I think the technique involves placing a pid entry in the config dictionary but I have no idea how this would be used with config admin.
A guide or simple example of how to set the configuration using this method would be very helpful.
I know it is some time since the question was asked, but I ran into the same problem when trying to create a ManagedServiceFactory-like Component with Declarative Services. So I want to share my solution. Maybe others find it useful. My problem was like this:
I have defined a component (annotated with #Component). On each configuration I add using felix file-install, I want an instance of that component created with the given configuration and activated immediately.
First I tried messing with the properties factory and configurationPid of #Component, but all that is not needed and even returns wrong results (felix annotation processor in the maven plugin seems to have a bug when handling configurationPid).
The solution I came up with:
package com.example.my;
#Component(
name = MyExampleComponent.FACTORY_PID,
configurationPolicy = ConfigurationPolicy.REQUIRE,
property = {"abc=", "exampleProp="}
)
public class MyExampleComponent {
public static final String FACTORY_PID = "com.example.my.component";
#Activate
protected void activate(BundleContext context, Map<String,Object> map) {
// ...
}
}
Then I created a config file for felix file-install named com.example.my.component-test1.cfg:
abc = Hello World
exampleProp = 123
When deployed this automatically creates a folder structure in the configuration folder like com/example/my/component containing the files:
factory.config
contents:
factory.pid="com.example.my.component"
factory.pidList=[ \
"com.example.my.component.525ca4fb-2d43-46f3-b912-8765f639c46f", \
]
.
525ca4fb-2d43-46f3-b912-8765f639c46f.config
contents:
abc="Hello World"
exampleProp="123"
felix.fileinstall.filename="file:/..._.cfg"
service.factoryPid="com.example.my.component"
service.pid="com.example.my.component.525ca4fb-2d43-46f3-b912-8765f639c46f"
The 525ca4fb-2d43-46f3-b912-8765f639c46f seems to be some randomly generated ID (possibly UUID).

Resources