spring mongo query testing - mongodb

I would like to set up a test (unit or integration test) for a mongo query.
I would like to test the following function:
public ArrayList<Document> search(){
Document textSearch = new Document("$text",new
Document("$search",text));
return randomCollection.find(textSearch).into(new ArrayList<Document>());
}
Im using MongoTemplate to get the mongo collection randomCollection

#SpringBootTest can be used to bootstrap all your Spring configurations. If you will write a test (which you should always do, your test will look something like this):
#RunWith(SpringRunner.class)
#SpringBootTest
public class SomeArbitraryTests {
#Autowired
private ArbitraryResource someResource;
#Test
public void someTest() {
someResource.search(...);
// assertions
}
}
If you would want to add an Embedded Mongodb for your testing purposes, then you might want to add some additional dependencies to your project:
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
Hope this helps!

Related

Soring Data Reactive: Criteria API reactive

I'm moving my repositories into reactive repositories.
I'm using webflux:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
Here my class:
#RequiredArgsConstructor
public class QdCFCriteriaRepository {
#PersistenceContext
private final EntityManager entityManager;
private final SessionFactory sessionFactory;
#Override
public List<QdCF> findByDataBaixaNull() {
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<QdCF> criteriaQuery = criteriaBuilder.createQuery(QdCF.class);
Root<QdCF> qdcf = criteriaQuery.from(QdCF.class);
Predicate dataBaixaPredicate = criteriaBuilder.isNull(qdcf.get("dataBaixa"));
criteriaQuery = criteriaQuery.where(dataBaixaPredicate);
TypedQuery<QdCF> query = this.entityManager.createQuery(criteriaQuery);
return query.getResultList();
}
}
I don't quite figure out how to move this criteria code to reactive criteria code.
I mean, How could I get a Mono of List<QdCF>?
Spring Data JPA does not support the Spring WebFlux. If you like Hibernate/JPA APIs and stick on the WebFlux statck, try to use Hibernate Reactive instead.
Unfortunately Spring Data team have no plan to integrate Hibernate Reactive, see:
https://github.com/spring-projects/spring-data-relational/issues/1178
https://github.com/spring-projects/spring-data-jpa/issues/2503
Reading my blog to integrate Hibernate Reactive with Spring yourself, it is just a piece of cake if you are familiar with Spring.

Creating SOAP client using Quarkus cannot import #CXFClient

Working with SOAP Web service in Quarkus using quarkiverse/quarkus-cxf
Try to implement a client using this example
import com.example.FruitWebService; // SEI
import javax.enterprise.context.ApplicationScoped;
import io.quarkiverse.cxf.annotation.CXFClient;
#Application // or any other CDI scope
public class MySoapClient {
#Inject #CXFClient
FruitWebService clientService;
public int getCount() {
return this.clientService.count();
}
}
Cannot import #CXFClient Im using the following quarkus-cxf extension
<dependency>
<groupId>io.quarkiverse.cxf</groupId>
<artifactId>quarkus-cxf</artifactId>
<version>0.7</version>
</dependency>
You need at least Version 0.8 of the plugin. So update your pom.xml to:
<dependency>
<groupId>io.quarkiverse.cxf</groupId>
<artifactId>quarkus-cxf</artifactId>
<version>0.8</version>
</dependency>

How to inject spring aop advice for MongoDb call?

I am new to Spring Aop, but I have case to implement AOP advice for a mongo db call(monog db update). I am trying in different way but getting 'Point cut not well formed' error or 'warning no match for this type name: arg string [Xlint:invalidAbsoluteTypeName]'(even if I give absolute name of the argument). Anyone can help on this as how to inject advice for mongo db update call?
#Aspect
#Component
public class DBStatsLoggerAspect {
private static final Logger log = LoggerFactory
.getLogger(DBStatsLoggerAspect.class);
private static final Document reqStatsCmdBson = new Document(
"getLastRequestStatistics", 1);
private DbCallback<Document> requestStatsDbCallback = new DbCallback<Document>() {
#Override
public Document doInDB(MongoDatabase db) throws MongoException,
DataAccessException {
return db.runCommand(reqStatsCmdBson);
}
};
#After("execution( public * com.mongodb.client.MongoCollection.*(..)) && args(org.bson.conversions.Bson.filter,..)")
public void requestStatsLoggerAdvice(JoinPoint joinPoint) {
MongoTemplate mongoTemplate = (MongoTemplate) joinPoint.getTarget();
log.info(mongoTemplate.execute(requestStatsDbCallback).toJson());
}
}
Actual db call method where I need to inject advice:(filter, updatePart all are org.bson.conversions.Bson data type) and here 'collection' is com.mongodb.client.MongoCollection.collection
Document result = collection.findOneAndUpdate(filter, updatePart, new FindOneAndUpdateOptions().upsert(false));
I am not a Spring or MongoDB user, just an AOP expert. But from what I see I am wondering:
You are intercepting execution(public * com.mongodb.client.MongoCollection.*(..)), so joinPoint.getTarget() is a MongoCollection type. Why do you think you can cast it to MongoTemplate? That would only work if your MongoCollection happened to be a MongoTemplate subclass. To me this looks like a bug.
Class MongoCollection is not a Spring component but a third-party class. Spring AOP can only intercept Spring component calls by means of creating dynamic proxies for those components and adding aspect interceptors to said proxies. so no matter how correct or incorrect your pointcut, it should never trigger.
What you can do instead is switch from Spring AOP to full-blown AspectJ. The standard way to do this is to activate AspectJ load-time weaving (LTW).

How I should configure a POJO class to enable it to be used as a resource in JAX-RS rest service? (Liferay 7.1)

I can use String object in JAX-RS rest service but not able to use POJO object. How I should configure a POJO class to enable it to be used as a resource in JAX-RS rest service?
DTO class
public class RestServiceDTO {
private String groupId;
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId)
this.groupId = groupId;
}
#Override
public String toString() {
return "RestServiceDTO [groupId=" + groupId + "]";
}
}
Rest service:
#Component(
immediate = true,
property = {
JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE + "=/greetings",
},
service = Application.class
)
public class RestServiceApplication extends Application {
public Set<Object> getSingletons() {
return Collections.<Object>singleton(this);
}
#POST
#Path("/post")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String test(RestServiceDTO dto) {
String groupid = dto.getGroupId();
return "{'groupid':'" + groupid + "'}";
}
}
Error:
2019-02-12 13:33:58.021 ERROR [http-nio-8080-exec-1][JAXRSUtils:83] No
message body reader has been found for class com.dto.RestServiceDTO,
ContentType: application/json
Since version 7.1 Liferay supports the OSGi JAX-RS Whiteboard specification, which means support for JAX-RS 2.1 using CXF, which also mean that there is support for JAXB annotated POJOs.
If you need to return a simple POJO you would normally be OK just by annotating your POJO class with #XmlRootElement.
Make sure you get JAXB runtime support attached to your application by requiring it on your application component configuration putting the property osgi.jaxrs.extension.select=(osgi.jaxrs.name=jaxb-json) on your application component.
This property will instruct the JAX-RS whiteboard to not start your application until the extension is present and ready for your application.
Since Liferay 7.2 the JAXB default implementation has been changed to Jackson. There is no configuration change needed, but now every POJO can be serialized to JSON even if the POJO is not annotated. Just make sure the jaxb runtime support is attached to your application the same as above.
In both 7.1 and 7.2 you can check the status of your JAX-RS applications, and attached extensions, using the gogo shell command jaxrs:check
Liferay uses the Apache CXF implementation of JAX-RS. As #dkb mentioned in the comments you need to provide the annotation that you have in the sample code.
You need to add the dependencies. See the list below and note that some are provided by the platform but some needs to be included in your jar and don't forget the transitive dependencies.
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-core</artifactId>
<version>3.0.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.0.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>3.0.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.7.9</version>
</dependency>
The last thing is. You need to register your Jackson provider within the JAX-RS app. It is done in teh applicaiton class for example like this (there are more ways how to do it).
#Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
singletons.add(getJacksonProvider());
return Collections.unmodifiableSet(singletons);
}
Add dependency
for MAVEN:
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.9.10</version>
</dependency>
for GRADLE:
compileOnly group: 'com.fasterxml.jackson.jaxrs', name: 'jackson-jaxrs-json-provider', version: '2.9.10'
now add this method in your Apllication class
private JacksonJsonProvider getJacksonJsonProvider() {
JacksonJsonProvider jacksonJsonProvider = new JacksonJsonProvider();
ObjectMapper objectMapper = new ObjectMapper();
// Prevent serialization of null and empty string values
objectMapper.setSerializationInclusion(Include.NON_EMPTY);
jacksonJsonProvider.setMapper(objectMapper);
jacksonJsonProvider.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return jacksonJsonProvider;
}
now change the code of getSingletons() method of your Application class to
#Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
singletons.add(this);
singletons.add(getJacksonJsonProvider());
return Collections.unmodifiableSet(singletons);
}
now I think you have to change your return statement to
return Response.ok(JSONFactoryUtil.looseSerializeDeep("{'groupid':'" + groupid + "'}"), MediaType.APPLICATION_JSON).build();
but I am not sure that you have to change your return statement or yours one will run ok

Can I generate a Spring Feign client with Multipart parameters?

I am getting the error:
"Method has too many Body parameters"
when trying to generate a Spring Feign client
#RequestMapping(value="/media", method=RequestMethod.POST)
String uploadMedia(#RequestHeader("Authentication") String token,
#RequestPart("media") MultipartFile audio,
#RequestPart("a-json-object") SomeClass someClazz,
#RequestPart("another-json-object") AnotherClass anotherClazz);
I found the following solution, which works when using regular Feign annotations, but not with Spring MVC annotations:
'Too many body parameters' Exception on Feign Client
It should be possible now. Add the following dependencies:
<dependencies>
...
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>2.2.0</version>
</dependency>
...
and use this client configuration:
#FeignClient(name = "file-upload-service", configuration = FileUploadServiceClient.MultipartSupportConfig.class)
public interface FileUploadServiceClient extends IFileUploadServiceClient {
#Configuration
public class MultipartSupportConfig {
#Bean
#Primary
#Scope("prototype")
public Encoder feignFormEncoder() {
return new SpringFormEncoder();
}
}
}
Example was taken from: feign-form docs