Fongo - OperationExecutor not found - spring

I would like to use fongo 2.0.x in my Spring boot application, but I getting errror
Error:(23, 44) java: cannot access com.mongodb.operation.OperationExecutor
class file for com.mongodb.operation.OperationExecutor not found
Here is my AbstractMongoConfiguration
#Configuration
#ComponentScan("com.foo")
public class MongoDbConfig extends AbstractMongoConfiguration {
#Override
protected String getDatabaseName() {
return "demo";
}
#Override
public Mongo mongo() throws Exception {
return new Fongo(getDatabaseName()).getMongo(); //this line throws the error
}
}

From the Fongo documentation:
It has a "provided" dependency on the mongo-java-driver and was tested with 2.13.0 and 3.0.1.
So Fongo wants mongo-java-driver on the classpath, and I'm guessing you don't have it (or at least not in the test scope).
So make sure the following is in your build script:
For Maven:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.4.1</version>
<scope>test</scope>
</dependency>
For Gradle:
testCompile 'org.mongodb:mongo-java-driver:3.4.1'

Related

Unit testing errors with #EmbeddedKafka and spring boot

I have IdentManagerApp with regular SpringBoot 2.6.8 and Kafka producers and consumers. Additionally I have custom Kafka configurations and failure scenarios handling with Retry/DLT topics. The respective factories creation need beans like :
ConcurrentKafkaListenerContainerFactory,
ConcurrentKafkaListenerContainerFactoryConfigurer configurer,
ConsumerFactory<Object, Object> kafkaConsumerFactoryOriginalToRetry,
KafkaTemplate<String, String> kafkaTemplate,
KafkaListenerEndpointRegistry registry,
etc
While all of that works smooth while running application, it doesnt go well while running Junits.
I keep getting errors like -
'org.springframework.boot.autoconfigure.kafka.ConcurrentKafkaListenerContainerFactoryConfigurer' that could not be found.
OR
Field registry in <package> required a bean of type 'org.springframework.kafka.config.KafkaListenerEndpointRegistry' that could not be found.
I fix one and other one pops up.
Is EmbeddedKafka compatible with exhaustive unit testing for springboot + Kafka ?
My simple test config looks like -
Main class :
#DirtiesContext
#EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:8888", "port=8888" })
#EnableKafkaCustomization
#SpringBootTest(classes = IdentManagerApp.class)
class OrchestratorAppTests {
#Test
void contextLoads() {
}
}
Ultra simple test class, doesnt even have Kafka related operations yet -
#ExtendWith(MockitoExtension.class)
#Import({
KafkaConfiguration.class
})
#ContextConfiguration
#WebMvcTest(controllers = IncomingRequestController.class)
public class IncomingRequestControllerTest { . . . . . }
Pom has below with Springboot's 2.6.8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<scope>test</scope>
</dependency>

How to configure Oracle XA Datasource on spring boot app that communicating with an EJB in JBoss EAP

I'm trying to use an EJB on a Spring boot application. This application runs in 'undertow' and it can call an EJB on a JBoss EAP (Jboss EAP 7.0).
I tried to configure the application to use Oracle XA transactions without success.
What I need is that when the Spring boot app calls the EJB and, after the call, some failure occurs on this app that EJB does a rollback the previous work.
Follows some configurations of the spring boot app:
pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-ejb-client-bom</artifactId>
<version>17.0.0.Final</version>
<type>pom</type>
</dependency>
</dependencies>
properties
spring.datasource.url=jdbc:oracle:thin:#<host>:<port>:<data>
spring.datasource.username=user
spring.datasource.password=pass
spring.datasource.xa.data-source-class-name=bitronix.tm.resource.jdbc.lrc.LrcXADataSource
spring.datasource.xa.properties.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.jpa.properties.hibernate.hbm2ddl.schema_filter_provider=<class>
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.integration.envers.enabled=false
App Class
Configuration
#SpringBootApplication
#EnableTransactionManagement
#ComponentScan(basePackages={...,...})
#EntityScan(basePackages={...,...,...})
public class SpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootApplication .class, args);
}
EJB 'producer'
#Configuration
public class EJBConfiguration {
#Bean
public Context context() throws NamingException {
Properties jndiProps = new Properties();
jndiProps.put("java.naming.factory.initial", "org.jboss.naming.remote.client.InitialContextFactory");
jndiProps.put("jboss.naming.client.ejb.context", true);
jndiProps.put("java.naming.provider.url", "http-remoting://localhost:8081");
return new InitialContext(jndiProps);
}
#Bean
public EJBRemote(Context c) throws NamingException {
return (EJBRemote) c.lookup("full EJB remote name")
}
}
the call of EJB is made as follows:
stuff
Spring boot App controller
class AppControler {
#AutoWired
Service service
#PostMapping("/")
#Transactional
public ResponseEntity controllerMethod() {
return new ResponseEntity<>(this.service.doStuff(), HttpStatus.OK);
}
}
Spring boot app service
class Service {
#Autowired
private EJBRemote EJBRemote;
#Autowired
private DAOObject dao;
#TransactionAttribute(TransactionAttributeType.MANDATORY)
Public Object doStuff() {
dao.save();
EJBRemote.saveSomeThing(); // OK operation, needs to rolback if oerros occurs after
dao.saveOtherThing();// errors occurs
}
}
the EJB implementation class on JBoss EAP is like
class EJBRemoteImpl implements EJBRemote {
#Override
public void saveSomeThing() {
someDao.save();
}
}
So when a error occurs in 'dao.saveOtherThing();' the operation made in 'EJBRemove.saveSomeThing();' needs to rolback.
If I'm put '#TransactionAttribute(TransactionAttributeType.MANDATORY)' on EJB this error occurs:
javax.ejb.EJBTransactionRequiredException: WFLYEJB0062: A transaction is required to call org.jboss.invocation.InterceptorContext#493c9dbb
at org.jboss.as.ejb3.tx.CMTTxInterceptor.mandatory(CMTTxInterceptor.java:289) ~[na:na]
at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:233) ~[na:na]
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) ~[na:na]
at org.jboss.as.ejb3.remote.EJBRemoteTransactionPropagatingInterceptor.processInvocation(EJBRemoteTransactionPropagatingInterceptor.java:79) ~[na:na]
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) ~[na:na]
at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41) ~[na:na]
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) ~[na:na]
at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:43) ~[na:na]
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) ~[na:na]
.
.
.
If the annotation (#TransactionAttribute(TransactionAttributeType.MANDATORY)) is not present the calls to EJB occurs normally but the rollback not occurs.
You are trying create an EJB transaction in a Spring Service, if you want do it you need convert your service to an EJB, so automatically all operations will be TransactionAttribute.REQUIRED, if you want that this method work with a Spring transaction, you need to use #Transactional(propagation = Propagation.MANDATORY) from Spring (org.springframework.transaction.annotation.Transactional), but I don't know if an Spring transaction works in distributed context, but you can try. If not converting the Bean to EJB will work.

Spring Boot test tries to initialize cache2k for the 2nd time and fails

After adding cache2k to my project some #SpringBootTest's stopped working with an error:
java.lang.IllegalStateException: Cache already created: 'cache'
Below I provide the minimal example to reproduce:
Go to start.spring.io and create a simplest Maven project with Cache starter, then add cache2k dependencies:
<properties>
<java.version>1.8</java.version>
<cache2k-version>1.2.2.Final</cache2k-version>
</properties>
<dependencies>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-api</artifactId>
<version>${cache2k-version}</version>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-core</artifactId>
<version>${cache2k-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-spring</artifactId>
<version>${cache2k-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Now configure the simplest cache:
#SpringBootApplication
#EnableCaching
public class CachingDemoApplication {
public static void main(String[] args) {
SpringApplication.run(CachingDemoApplication.class, args);
}
#Bean
public CacheManager springCacheManager() {
SpringCache2kCacheManager cacheManager = new SpringCache2kCacheManager();
cacheManager.addCaches(b -> b.name("cache"));
return cacheManager;
}
}
And add any service (which we will #MockBean in one of our tests:
#Service
public class SomeService {
public String getString() {
System.out.println("Executing service method");
return "foo";
}
}
Now two #SpringBootTest tests are required to reproduce the issue:
#SpringBootTest
#RunWith(SpringRunner.class)
public class SpringBootAppTest {
#Test
public void getString() {
System.out.println("Empty test");
}
}
#RunWith(SpringRunner.class)
#SpringBootTest
public class WithMockedBeanTest {
#MockBean
SomeService service;
#Test
public void contextLoads() {
}
}
Notice that the 2nd test has mocked #MockBean. This causes an error (stacktrace below).
Caused by: java.lang.IllegalStateException: Cache already created: 'cache'
at org.cache2k.core.CacheManagerImpl.newCache(CacheManagerImpl.java:174)
at org.cache2k.core.InternalCache2kBuilder.buildAsIs(InternalCache2kBuilder.java:239)
at org.cache2k.core.InternalCache2kBuilder.build(InternalCache2kBuilder.java:182)
at org.cache2k.core.Cache2kCoreProviderImpl.createCache(Cache2kCoreProviderImpl.java:215)
at org.cache2k.Cache2kBuilder.build(Cache2kBuilder.java:837)
at org.cache2k.extra.spring.SpringCache2kCacheManager.buildAndWrap(SpringCache2kCacheManager.java:205)
at org.cache2k.extra.spring.SpringCache2kCacheManager.lambda$addCache$2(SpringCache2kCacheManager.java:143)
at java.util.concurrent.ConcurrentHashMap.compute(ConcurrentHashMap.java:1853)
at org.cache2k.extra.spring.SpringCache2kCacheManager.addCache(SpringCache2kCacheManager.java:141)
at org.cache2k.extra.spring.SpringCache2kCacheManager.addCaches(SpringCache2kCacheManager.java:132)
at com.example.cachingdemo.CachingDemoApplication.springCacheManager(CachingDemoApplication.java:23)
at com.example.cachingdemo.CachingDemoApplication$$EnhancerBySpringCGLIB$$2dce99ca.CGLIB$springCacheManager$0(<generated>)
at com.example.cachingdemo.CachingDemoApplication$$EnhancerBySpringCGLIB$$2dce99ca$$FastClassBySpringCGLIB$$bbd240c0.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
at com.example.cachingdemo.CachingDemoApplication$$EnhancerBySpringCGLIB$$2dce99ca.springCacheManager(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 52 more
If you remove #MockBean, both tests will pass.
How can I avoid this error in my test suite?
Your second test represents a different ApplicationContext altogether so the test framework will initiate a dedicated one for it. If cache2k is stateful (for instance sharing the CacheManager for a given classloader if it already exists), the second context will attempt to create a new CacheManager while the first one is still active.
You either need to flag one of the test as dirty (see #DirtiesContext) which will close the context and shut down the CacheManager, or you can replace the cache infrastructure by an option that does not require all that, see #AutoConfigureCache.
If cache2k works in such a way that it requires you to dirty the context, I'd highly recommend to swap it using the later options.
Since I do not want any custom behavior in test, but just want to get rid of this error, the solution is to create CacheManager using unique name like this:
#Bean
public CacheManager springCacheManager() {
SpringCache2kCacheManager cacheManager = new SpringCache2kCacheManager("spring-" + hashCode());
cacheManager.addCaches(b -> b.name("cache"));
return cacheManager;
}
I encountered the same error when using cache2k with Spring Dev Tools, and ended up with the following code as the solution:
#Bean
public CacheManager cacheManager() {
SpringCache2kCacheManager cacheManager = new SpringCache2kCacheManager();
// To avoid the "Caused by: java.lang.IllegalStateException: Cache already created:"
// error when Spring DevTools is enabled and code reloaded
if (cacheManager.getCacheNames().stream()
.filter(name -> name.equals("cache"))
.count() == 0) {
cacheManager.addCaches(
b -> b.name("cache")
);
}
return cacheManager;
}

Spring Boot upgrade can't add RequestContextListener

So I just upgraded my Spring Boot web app to 2.0.0, In my main Application class I have this method:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext rootAppContext = createRootApplicationContext(servletContext);
if (rootAppContext != null) {
servletContext.addListener(new RequestContextListener());
}
else {
logger.debug("No ContextLoaderListener registered");
}
}
But now I am getting a compile error:
The method addListener(RequestContextListener) is undefined for the type ServletContext
What's weird is that the ServletContext is the problem, not Spring boot. It no longer has any add* methods. Did Spring5/Boot2 upgrade the servlet specs, and
What is the correct way to do this now?
It was a ServletContext issue. Spring boot 2 uses servlet specs 3.1.0, and apparently no longer support 2.5, which is what I had in my pom. So I replaced it with this:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
And it worked fine. Hope this helps someone.

AnnotationConfigRegistry not found in spring 4

I am having an strange behavior, using spring 4.1.1 I get this error.
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project newvalia-view: Compilation failure
[ERROR] /C:/Users/edu/IdeaProjects/newvalia/newvalia- view/src/main/java/com/newvalia/web/init/WebInitContext.java:[19,12] cannot access org.springframework.context.annotation.AnnotationConfigRegistry
[ERROR] class file for org.springframework.context.annotation.AnnotationConfigRegistry not found
while if I downgrade to spring 4.0.7 it compiles correctly.
I am using simple spring webmwc configuration :
#Configuration
#ComponentScan(value = "com.newvalia.web")
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
}
public class WebInitContext implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(WebMvcConfig.class);
ctx.setServletContext(container);
Dynamic servlet = container.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
is this a new expected behavior?
import org.springframework.context jar correctly in your pom file , and thats it .
Hope that Helps .
Add spring context dependency :
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>

Resources