Soring Data Reactive: Criteria API reactive - spring-data

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.

Related

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 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

spring mongo query testing

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!

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

How to pass Calendar param as input to a rest service?

Here is what I am trying to do:
#POST
#Path("/MyPath")
#Produces("text/xml")
#RolesAllowed({"user"})
public Output myMethod (#QueryParam("itemId") long ItemId,
#QueryParam("plannedstartdate") Calendar plannedStartDate,
#QueryParam("plannedreturndate") Calendar plannedReturnDate)
I am using JBoss AS7. As far as I understan, resteasy is integrated into JBoss AS7. I am able to run simple rest services.
The only documentation I found about passing dates is at the link :
http://docs.jboss.org/resteasy/2.0.0.GA/userguide/html/StringConverter.html#StringParamUnmarshaller
I am not able to follow this and fix the issue as the instructions are not clear.
When I try to create an annotation DateFormat as given in the example, it does not recognize StringParamUnmarshaller. I don't know where to get it from. If resteasy is already integrated into JBoss AS7, is this not supposed to be recognized?
My pom.xml has the following dependency:
<!-- Import the JAX-RS API, we use provided scope as the API is included
in JBoss AS 7 -->
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_1.1_spec</artifactId>
<scope>provided</scope>
</dependency>
The calls to this method fail as the String to Calendar conversion does not happen. I dont want to pass String instead of Calendar as there are other clients that make java call directly. Can anyone help with how I can pass dates to Rest Calls?
Thanks
Veer
This issue is resolved. See the following code.
Create an Annotation class CalendarFormat.java:
#Retention(RUNTIME)
#StringParameterUnmarshallerBinder(CalendarFormatter.class)
public #interface CalendarFormat {
String value();
}
Add a class CalendarFormatter.java:
public class CalendarFormatter implements StringParameterUnmarshaller<Calendar> {
private SimpleDateFormat formatter;
public void setAnnotations(Annotation[] annotations) {
CalendarFormat format = FindAnnotation.findAnnotation(annotations, CalendarFormat.class);
formatter = new SimpleDateFormat(format.value());
}
public Calendar fromString(String str) {
try {
Calendar cal = Calendar.getInstance();
cal.setTime(formatter.parse(str));
return cal;
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
Add to POM
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>2.3.3.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
<version>2.3.4.Final</version>
<exclusions>
<exclusion>
<artifactId>resteasy-jaxrs</artifactId>
<groupId>org.jboss.resteasy</groupId>
</exclusion>
</exclusions>
</dependency>
Change the method signature to use the annotation
#POST
#Path("/MyPath")
#Produces("text/xml")
#RolesAllowed({"user"})
public Output myMethod(#QueryParam("itemId") long ItemId,
#QueryParam("plannedstartdate") #CalendarFormat("MM-dd-yyyy") Calendar plannedStartDate,
#QueryParam("plannedreturndate") #CalendarFormat("MM-dd-yyyy") Calendar plannedReturnDate)
That's it.
It's not possible to use java.util.Calendar as an argument of #QueryParam, because it doesn't have a one-arg constructor that accepts String. The only option you have is to introduce a new class QueryCalendar, which will have one-arg constructor and will return Calendar (or inherit it).
More information about who can be an argument: http://docs.oracle.com/javaee/6/api/javax/ws/rs/QueryParam.html