Vaadin with SpringBoot - Redis serialization error - spring-boot

Trying to use SpringSession with Redis storage together with my Vaadin App running under SpringBoot. Session works fine with SpringBoot controllers in my app. But when displaying VaadinUI, even a simple one without any #Autowired beans etc, (example below), I'm getting the following error.
org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.io.NotSerializableException: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
I found similar post here NotSerializableException on serialization of objects currently shown by Vaadin but solution doesnt work for me. I found even this Vaadin ticket https://dev.vaadin.com/ticket/19462 but #SerializableProxy has no efect in the simple UI below as there is no #Autowired bean here and error is still there. Any idea how to resolve this? Database (Redis, memcached etc. ) session storage is very important for load balanced solution we try to build.
#SpringUI(path="/simple")
public class SimpleUI extends UI implements Serializable {
private static final long serialVersionUID = 1L;
#Override
protected void init(VaadinRequest request) {
}
}

It is a known bug. You need to provide your own SpringUiProvider.
https://dev.vaadin.com/ticket/19462

Related

Is it possible to test specific Spring REST endpoint security and avoid bootstrapping database connection?

We have a couple of Spring tests that call a secured controller endpoints. Our goal is to assure that absence of particular user roles will result into HTTP 403 status.
Our issue is that execution of those tests also bootstraps DB connection which we don't actually need.
I've already tried countless number of all kind of annotations and manual configurations to avoid initialization of DB connection but so far without luck. Can you please share example how to do that?
We use Spring Boot 2.7.
Yes, you can use #WebMvcTest, take a look at the docs. In summary, using #WebMvcTest will only bootstrap the Spring MVC components and avoid loading other application's layers. This annotation also automatically configures Spring Security for you, therefore you can test authentication/authorization rules.
Example:
#WebMvcTest(UserVehicleController.class)
class MyControllerTests {
#Autowired
private MockMvc mvc;
#MockBean
private UserVehicleService userVehicleService;
#Test
#WithMockUser(roles = "ADMIN")
void testAdminSuccess() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().string("Honda Civic"));
}
#Test
#WithMockUser(roles = "USER")
void testUserForbidden() throws Exception {
this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isForbidden());
}
}

Hazelcast Cache Manager: Cannot overwrite a Cache's CacheManager

On an application I am working I am trying to upgrade from Hazelcast 3.6 to 3.12.4 and I am encountering some problems which reproduce easily when two or more tests are ran together. The tests are all annotated with #WebAppConfiguration and include the Spring's application configuration using ContextConfiguration(classes = {AppConfig.class})
As part of the configuration, I have a #Bean that called CacheAwareStorage that initiates the CacheManager. THe initialization is quite basic:
public Cache<T, V> initCache(String name, Class<T> type, Class<T> valueType) {
Cache<T, V> cache = manager.getCache(cacheName, keyType, valueType);
if (cache != null)
{
return cache;
}
cache = manager.createCache(cacheName, config);
return cache;
}
The problem occurs when the context is refreshed as part of the test suit, which I think is done in AbstractTestNGSpringContextTests since I don't explicitly refresh the context. The following error occurs which result sin only the first class of tests to pass:
GenericWebApplicationContext: Refreshing org.springframework.web.context.support.GenericWebApplicationContext#6170989a
....
WARN GenericWebApplicationContext: Exception encountered during context initialization - cancelling refresh attempt
....
Factory method 'tokenStore' threw exception
nested exception is java.lang.IllegalStateException: Cannot overwrite a Cache's CacheManager.
Looking over what has changed, I see that the AbstracthazelcastCacheManager throws an IllegalStateException which comes from the Hazelcast CacheProxy. To be more precise, the manager.getCache() -> getCacheUnchecked() -> creates a cache proxy in createCacheProxy() -> and set's the proxy's manager to the current manager in cacheProxy.setCacheManager().
Starting with Hazelcast v3.9, this is no longer allowed once the manager has already been set.
What would be a solution for this? It may be that there is a bug in Hazelcast (there is no check if the manager that is being set is actually different than the already existing one), however I am looking for something that I can do on my side. Why the 'getCache()' tries to re-create the proxy is another thing that I do not understand.
I assume that I must do something so that the Context is not refreshed, however I don't know how (if at all) I can do that.
The problem was due to the way the Cache manager Bean was created. I used the internal Hazelcast cache manager and a new instance was created each time. Using the JCache API as bellow, solved the problem
#Bean
public CacheManager cacheManager() {
HazelcastServerCachingProvider provider = Caching.getCachingProvider(); // or add class name of Hazelcast server caching provider to disambiguate
return provider.getCacheManager(null, null, HazelcastCachingProvider.propertiesByInstanceItself(HAZELCAST_INSTANCE));
}
Help received from Hazelcast team on this: https://github.com/hazelcast/hazelcast/issues/16212

java.lang.ClassCastException: DTOObject cannot be cast to DTOObject

I am facing a weird issue in my application which runs on Spring Boot 1.4.0M3 which is using Spring cache implementation where provider is Redis where I receive classCastException that same object cannot be casted
I am using Mongodb as database and I have User Object which contains List of Roles object loaded lazily and Roles internally contains Permissions Object like below
#Document
#Data
public class User implements Serializable{
private String passwordResetToken;
private boolean enabled = false;
#DBRef(lazy= true)
private List<Role> roleList;
}
My Role DTO is as below
#Data
#Document
public class Role implements Serializable{
private String roleName;
private String description;
#DBRef(lazy= true)
private List<Permission> permissions;
}
Now in my spring MVC while loading all roles I am calling all permissions and since this is repetitive operation I thought of caching the result and using redis and while loading the roles value I receive below exception.
raised java.lang.ClassCastException: com.learning.securedapp.domain.Permission cannot be cast to com.learning.securedapp.domain.Permission
Help me to overcome this error.
I am attaching the source code to my project and I receive error at line 91 of RoleController.java
To Replicate in your local environment login to application and click on permissions menu and then roles menu, In Roles menu now click on any edit icon.you will receive above error.
When you use DevTools with caching, you need to be aware of this limitation.
When the object is serialized into the cache, the application class loader is C1. Then after you change some code/configuration, devtools automatically restart the context and creates a new classloader (C2). When you hit that cache method, the cache abstraction finds an entry in the cache and it deserializes it from the store. If the cache library doesn't take the context classloader into account, that object will have the wrong classloader attached to it (which explains that weird exception A cannot be cast to A).
TL;DR do not serialize classes with devtools if the cache library doesn't use the context classloader. Or put your cache library in the application classloader:
restart.include.yourcache=/my-cache-lib-[\\w-]+\.jar
This worked for me , DevTools and Redis both are working. We need to pass classLoader when creating JdkSerializationRedisSerializer and it should work
JdkSerializationRedisSerializer redisSerializer = new JdkSerializationRedisSerializer(getClass().getClassLoader());
So my RedisCacheConfig is:
#Configuration
#EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport implements CachingConfigurer {
............................
............................
#Bean
public RedisCacheManager redisCacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
JdkSerializationRedisSerializer redisSerializer = new JdkSerializationRedisSerializer(getClass().getClassLoader());
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofHours(redisDataTTL))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer));
redisCacheConfiguration.usePrefix();
RedisCacheManager redisCacheManager = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(lettuceConnectionFactory)
.cacheDefaults(redisCacheConfiguration)
.build();
redisCacheManager.setTransactionAware(true);
return redisCacheManager;
}
............................
............................
}
Check this spring boot issue: https://github.com/spring-projects/spring-boot/issues/9444
I actually tried the proposed solution (and many variations thereof) with no luck. E.g., this didn't stop the problem from occurring:
restart.include.cache=/spring-data-redis-.*.jar
I updated the above to callout the specific version I was using and it still didn't work.
What I ended up doing which did work was to exclude spring-boot-devtools from my project. I'm using Maven so the annotation was this:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>[1.5.9,)</version>
<scope>provided</scope>
</dependency>
This will prevent any version equal to or greater than 1.5.9 from loading up. After I included the above, everything worked as expected. I know this isn't an ideal solution for all, but I made little use of the restart functions of devtools so this was actually a good approach for me.
I am using Spring Boot 2.0.5, and I ended up removing devtools altogether from pom.xml. Thanks to the answer above from #Always Learning.
As much as I hate to do this, but I can't find another way for now!
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
-->

bitronix transaction manager

I'm trying to migrate from JPA to JTA and use bitronix transaction manager. I'm getting below error message when try to run unit tests. According to bitronix documentation this is normal b/c my spring context configuration is trying to load the resources twice (once in base class and then in the test class, see code below), I have tried the same with atomikos and I got similar result.
Caused by:
java.lang.IllegalArgumentException:
resource with uniqueName 'xyzDb'
has already been registered
My base class
#ContextConfiguration(locations = {"classpath:com/xyz/baseContext.xml"})
#Transactional
public abstract class AbstractTestSupport extends Assert implements ApplicationContextAware
{
In some unit tests I have to extend the test support and add a context config file like below. so it loads context once for base class and another time for child class and fails
Child class
#ContextConfiguration(locations = {"classpath:com/xyz/testContext.xml"})
public class UnitTest extends AbstractTestSupport
{
After the test I'm shutting down context, so next test works fine as long as it doesn't extend the base class with another context config file.
#AfterClass
public static void onTearDownAfterClass() throws Exception
{
applicationContext.shutdownApplicationContext();
assertFalse("Spring application context is still active after shutdown. ", applicationContext.isActive());
}
I want to keep context config files in the child classes and make this work like that, any ideas greatly appreciated....
The error message basically means you created the connection pool with unique name 'xyzDb' (remember there is a uniqueName property you need to set on BTM's pools?) for the second time at the time the exception is thrown. You cannot do that: each connection pool must have a unique name and must be closed before another one with an identical name can be created.
I suppose there is some overlap between your two context files causing this or maybe the connections pools aren't always closed like they should. Unfortunately you published too little information to get a definitive answer.

flex blazeds spring exception translator

I am using spring exception translator to wrap java exception into flex exception.
public void testException()throws Exception{
throw new Exception("my exception");
}
But for some reason, I am getting IllegalAccessError. The code sections are entering the testException and the Translator class.
Question:
Why it trying to get log target level? Can someone help me resolve this please.
Below is the lines from the log:
MyExceptionTranslatorImpl.translate()
class java.lang.IllegalAccessError
MyExceptionTranslatorImpl.translate()
java.lang.IllegalAccessError: tried to access method **flex.messaging.log.Log.getTargetLevel()S** from class flex.messaging.MessageException
MyExceptionTranslatorImpl.translate()
tried to access method
flex.messaging.log.Log.getTargetLevel()S from class flex.messaging.MessageException
[BlazeDS] tried to access method flex.messaging.log.Log.getTargetLevel()S from class flex.messaging.MessageException
[BlazeDS] Serializing AMF/HTTP response
This turned out to be mismatch in jars. Thank you Cornel Creanga for the initial response.
I also verified that throwing an java.lang.exception was enough to catch the error on the client side.

Resources