Spring Data Redis cache in json throws ClassCastException - spring-boot

this is sample project of spring-data-redis + caching. I'd like to store caches in redis in plain json, so I've configured GenericJackson2JsonRedisSerializer with objectMapper provided by spring.
Currently when I run test (the only one in application) I'm getting following error:
java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class com.github.bilakpoc.rediscachedemo.generated.model.ModelImport (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.github.bilakpoc.rediscachedemo.generated.model.ModelImport is in unnamed module of loader 'app')
at com.github.bilakpoc.rediscachedemo.service.ImportService$$EnhancerBySpringCGLIB$$14512ec6.getImportById(<generated>) ~[classes/:na]
Please can anybody share how to properly configure redis to store caches in json?
Thanks

Thanks for the reproducer. You do not need to configure redis cache from code. Only problem was "generated code was not serializable" send you the fix in https://github.com/bilak-poc/redis-cache-demo/pull/1
For future reference
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>${openapi-generator-maven-plugin.version}</version>
<executions>
<execution>
<id>openapi</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<apiPackage>${openapi-generator.package}.api</apiPackage>
<configOptions>
<interfaceOnly>true</interfaceOnly>
<serializableModel>true</serializableModel>
</configOptions>
<generatorName>spring</generatorName>
<invokerPackage>${openapi-generator.package}.handler</invokerPackage>
<inputSpec>${pom.basedir}/src/main/resources/openapi/openapi.yaml</inputSpec>
<modelPackage>${openapi-generator.package}.model</modelPackage>
<supportingFilesToGenerate>ApiUtil.java</supportingFilesToGenerate>
</configuration>
</execution>
</executions>
</plugin>
serializableModel should be added to configOptions. And #EnableCaching will be enough.
I left comments in CacheConfig. Actually found another workaround with Jackson2JsonRedisSerializer then I dig in more and found out the real problem.

Related

Overriding openAPI generated source

I am using Spring boot with openAPI generator maven plugin and getting the source generated under src/main/java using the below config :
<configuration>
<inputSpec>openapi.yaml</inputSpec>
<output>${project.basedir}</output>
<generatorName>java</generatorName>
<addCompileSourceRoot>true</addCompileSourceRoot>
<skipOverwrite>false</skipOverwrite>
<modelNameSuffix>Dto</modelNameSuffix>
<modelPackage>be.ordina.conference.api.model</modelPackage>
<generateModels>true</generateModels>
<generateModelTests>false</generateModelTests>
<generateModelDocumentation>true</generateModelDocumentation>
<generateApis>false</generateApis>
<generateSupportingFiles>false</generateSupportingFiles>
<library>jersey2</library>
<configOptions>
<dateLibrary>java8-localdatetime</dateLibrary>
<java8>true</java8>
<useBeanValidation>true</useBeanValidation>
<sourceFolder>src/java</sourceFolder>
</configOptions>
I want to modify generated Interface by changing few input parameter type,which i am doing under src/main/java.
Once the project is build again the changes are overridden by openAPI codegen.
I want to restrict that from happening.
Any pointers how to do that.

Spring - show git commit ID on custom health endpoint

I am trying to show the Git version info (branch, commit etc) on my custom health endpoint.
I tried using management.info.git.mode=full + git-commit-id-plugin but there is no direct way to extract the git info into a Java class. If there is, this will be the ideal way.
I also tried the same git-commit-id-plugin with Value annotations in my Java class like so #Value("${git.commit.id}") but Spring can't find the property values. I see the git.properties file created in the target dir.
What am I missing here? thanks in advance
We have to configure PropertyPlaceHolderConfigurer bean so that we can able to access the property file generated by the plugin, Please use the below code for your reference,
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer propsConfig
= new PropertySourcesPlaceholderConfigurer();
propsConfig.setLocation(new ClassPathResource("git.properties"));
propsConfig.setIgnoreResourceNotFound(true);
propsConfig.setIgnoreUnresolvablePlaceholders(true);
return propsConfig;
}
then in your custom health check class, you can use,
#Value("${git.commit.id}")
private String commitId;
I hope this will resolve your problem.
With Spring Boot 2 you can get this information using git-commit-id-plugin in info endpoint. This is how you can configure it
POM File
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
</plugin>
</plugins>
</build>
Sample Response http://localhost:8080/actuator/info
{
"git":{
"branch":"some-name",
"commit":{
"id":"ef569c2",
"time":1579000598.000000000
}
},
"build":{
"artifact":"xxx",
"name":"xxxx",
"time":1579020527.139000000,
"version":"0.0.1-SNAPSHOT",
"group":"xxxx"
}
}
The easies way is to use the commit plugin:
https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.build.generate-git-info
It generates git.properties. Then Spring autoconfiguration jumps in. When git.properties is available in the classpath, it creates GitProperties bean:
https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints.info.git-commit-information
Simply inject GitProperties to your bean and use it.

Externalized configuration for rpm

INTRO:
This question is fairly similar to How to put a directory first on the classpath with Spring Boot? and I've searched around a bit but unfortunately nothing worked so far. Neither changing to packaging=ZIP in the spring-boot-maven-plugin nor using loader.path as explained in boot features external config or how to - properties and configuration, so I must be missing something. One more thing, if possible I would like to avoid passing each and every configuration file as an argument with file://....
I have an application which originally was a simulator for several types of services: sftp, soap, etc. Initially it supported 1 instance of each server type configurable through a properties file.
I've now updated it to support multiple server instances on separate ports, and the configuration is done in a YAML file, and I've also migrated from classic spring to boot. Finally the application is delivered as an RPM, which has the following structure
installation-dir
|--bin
| '-- simulator.sh [lifecycle management script]
|--config
| |--application.properties
| |--log4j2.xml
| |--samples [sample files for various operations]
| | |-- sample1.csv
| | |-- sample2.csv
| | '-- sample3.csv
| |--simulators.yaml [simulators config]
| '--simulator.jks
|--lib
| '-- simulator-1.0.jar
'--log
'-- simulator.log
Before, simulators.sh launched the main class adding the config dir to the classpath, and spring would load the properties file without any issue:
java <other args> -cp "..." com.whatever.SimulatorLauncher
Since the migration, it now launches the generated jar, so the -cp is no longer used, and I'm having trouble making it pick up the configuration files:
java <other args> lib/simulator-1.0.jar
Ignoring for a bit the fact that it does not find aplication.properties, the simulators' config is loaded as below:
#Configuration
#ConfigurationProperties(locations = {"classpath:/simulators.yml"}, ignoreUnknownFields = false, prefix = "simulators")
public class SimulatorSettings {
private static final Logger log = LoggerFactory.getLogger(SimulatorSettings.class);
#NotNull
private List<SftpSettings> sftp;
#NotNull
private List<SoapSettings> soap;
Since the config should be updateable without having to repackage the application, all of the files are excluded from the resulting jar, but packaged in the rpm under config:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<excludes>
<!-- these files will be included in the rpm under config -->
<exclude>application.properties</exclude>
<exclude>log4j2.xml</exclude>
<exclude>samples/**</exclude>
<exclude>simulators.yml</exclude>
<exclude>simulator.jks</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.whatever.SimulatorLauncher</mainClass>
<layout>ZIP</layout>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>rpm-maven-plugin</artifactId>
<version>2.1.5</version>
...
<configuration>
...
<mapping>
<directory>${rpm.app.home}/config</directory>
<sources>
<source>
<location>src/main/resources</location>
<includes>
<include>application.properties</include>
<include>simulators.yml</include>
<include>log4j2.xml</include>
<include>nls-sim.jks</include>
</includes>
</source>
</sources>
<filemode>755</filemode>
</mapping>
Any help or hints are greatly appreciated.
I ended up removing the spring-boot-maven-plugin to prevent repackaging, and created the RPM with my artefact & its dependencies and launching the application like before:
java <other args> -cp "<installation dir>/config:...:<libs>" com.whatever.SimulatorLauncher
Still, I'd be interested to find out if anybody knows a way of doing it with a spring boot repackaged jar...

Spring cannot find class path resource

I googled my problem several times. Some of them was good, but not the solution for my problem. Since now, I took hours, to solve my problem.
I started a project in eclipse using maven.
After that, I added spring and hibernate as dependencies.
This project isnt a normal static void main() project.
It is a plugin, which i can implement in an other running program.
Now let me explain my problem:
When I try to start my plugin (FYI: putted it into /plugins folder of the main program), I get a I/O Exception:
org.bukkit.plugin.InvalidPluginException: org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [applicationContext.xml]; nested exception is java.io.FileNotFoundException:
class path resource [applicationContext.xml] cannot be opened because it does not exist
The applicationContext.xml is in my src/main/resources folder and also in my classpath. I checked it with winRar. After the build process, the applicationContext.xml was in the root directory.
CLICK TO OPEN THE IMAGE
I also use the apache maven-shade-plugin, to include all my dependencys.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<mainClass>com.lostforce.core.LostForceCore</mainClass>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
The applicationContext.xml can be found! I checked it with
System.out.println("Is null: " + (getClassLoader().getResourceAsStream("applicationContext.xml") == null));
This returned false for me!
I load the applicationContext.xml with this code:
context = new ClassPathXmlApplicationContext("applicationContext.xml");
I dont know why it happens.
All things I read about this problems, dont work.
My Project:
CLICK TO OPEN THE IMAGE
A little checklist:
- src/main/resource is in my classpath
- applicationContext.xml is in the src/main/resource folder
- build my proect with maven mvn: clean package
- Use the maven-shade-plugin to include dependencys
Hope anyone can help me. Thank you
I solved this problem!
Because my project is a plugin, I have to define a other classloader. So I Created this startup Method:
public class SpringBootstrap {
private final ClassLoader classLoader = SpringBootstrap.class.getClassLoader();
public ApplicationContext startupSpring() {
ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml") {
protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
super.initBeanDefinitionReader(reader);
reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
reader.setBeanClassLoader(classLoader);
setClassLoader(classLoader);
}
};
return context;
}
}

How to use org.eclipse.jetty.server.Request in a webapp?

In my ServletFilter, I want to use specific jetty API exposed in the HttpServletRequest implementation.
I launched it like that:
final Request jettyRequest = Request.getBaseRequest(request)
If I want to avoid ClassNotFoundException, I must add the jetty-server artifact to my maven dependencies. But if I do that, getBaseRequest returns null because 'request instanceof Request' returns false instead of true.
This is certainly due to conflict between jetty and application classloaders because both of them have loaded 'org.eclipse.jetty.server.Request' class. I tried several configurations, but I was not able to make the Request class exposed to my webapp without adding the dependency in WEB-INF/lib, which causes the classpath issue.
My application is launched with "mvn jetty:run-forked" and configured like this:
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty-version}</version>
<configuration>
<webAppSourceDirectory>${project.build.directory}/${project.name}</webAppSourceDirectory>
<systemProperties>
<force>true</force>
</systemProperties>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webAppConfig>
<contextPath>/</contextPath>
</webAppConfig>
<jettyXml>../jetty.xml,../jetty-ssl.xml,../jetty-https.xml</jettyXml>
<jvmArgs>-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn-version}/alpn-boot-${alpn-version}.jar</jvmArgs>
</configuration>
</plugin>
Any help will be appreciated!
I fixed the issue by adding a WebAppContext configuration file that contains:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="parentLoaderPriority">true</Set>
</Configure>
The file must be referenced in jetty-maven-plugin like that:
<contextXml>../jetty-context.xml</contextXml>

Resources