I'm trying to create a project that uses Hibernate Panache and Rest, similar to the quickstart on https://github.com/quarkusio/quarkus-quickstarts/tree/master/hibernate-orm-panache-resteasy.
When I try to #Post an entity that extends PanacheEntity, as shown below, I get the following error:
javax.ws.rs.ProcessingException: RESTEASY008200: JSON Binding deserialization error: Can't create instance
Entity
#Entity
#Cacheable
class Trade extends PanacheEntity {
#Column(length = 40, unique = true)
String name;
}
Rest resource
import javax.enterprise.context.ApplicationScoped;
import javax.transaction.Transactional;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
#Path("/trades")
#ApplicationScoped
#Produces("application/json")
#Consumes("application/json")
public class TradeReporterResource {
#POST
#Transactional
public Response add(Trade trade) {
System.out.println("begin");
//t.closePrice = trade.closePrice;
System.out.println("persisting");
trade.persist();
System.out.println("persisted");
return Response.ok(trade).build();
}
}
Pom dependencies
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bom</artifactId>
<version>${quarkus.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
</dependencies>
Problem appears to be with Penache
When I remove the extends PanacheEntity from the Trade entity, then at least I can POST successfully.
The problem turns out to be rather simple, all you need to do is make class Trade a public class.
It should be noted that this is not a Quarkus limitation, but a JSON-B limitation (which requires de-serialized classes to have a public or protected no-arg constructor - see section 3.7 of the JSON-B spec)
Related
I develop under MyEclipse a Jersey Java REST API which runs under Tomcat 9.
This API uses JWT tokens and I use io.jsonwebtoken to manage what I need to make it work.
Everything is fine except when my API calls a function which generates this error:
java.lang.NoSuchMethodError: 'int io.jsonwebtoken.SignatureAlgorithm.getMinKeyLength()'
at io.jsonwebtoken.security.Keys.hmacShaKeyFor(Keys.java:84)
at com.knowledgeplaces.metalmsapi.utils.JWTUtils.createJWT(JWTUtils.java:18)
Here is the code of JWTUtils:
package com.knowledgeplaces.metalmsapi.utils;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.WeakKeyException;
import java.security.Key;
import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
public class JWTUtils {
public String createJWT(String issuer, Integer userId, String jwtSecretKey, Integer jwtExpirationMs) throws Exception {
Key key;
try {
key = Keys.hmacShaKeyFor(jwtSecretKey.getBytes(StandardCharsets.UTF_8));
} catch (WeakKeyException ex) {
throw new Exception("invalidKPLMSCustomerConfigMetaLmsApiKey");
}
And here is pom.xml:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
Any help appreciated.
I removed the last dependency and it is fixed now.
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
I am developing a Quarkus service application let's call it Project2, this application depends on Project1 which has the Book class with Validation Annotations.
When an invalid JSON is provided then I do not get the invalid message from the Book class. However, if I place the Book class within Poject2 directly without any dependency then I get the error messages.
I would like to know how to get the error messages from the Dependency class which are coming from JAR?
Following is my Project2 which has the BookService:
import org.project1.com.Book;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
#Path("/api")
public class BookService {
#Path("/generateTestData")
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void generateTestData(#Valid final Book book){
System.out.println("After Successful Validation : " + book.toString());
}
}
Following is my Project1 Book class:
import lombok.Data;
import lombok.ToString;
import javax.validation.Valid;
import java.util.List;
#Data
#ToString
public class Book {
#NotNull(message="Book ID cannot be NULL")
#Min(value = 1, message="Book ID cannot be less than 1")
private int bookId;
#NotNull(message="Author name cannot be NULL")
private String author;
}
When I make a invalid request from Postman to http://localhost:8080/api/generateTestData then I do not get any validation messages (bookId should be >= 1 to be a valid input):
{
"bookId" : 0,
"author" : "Batman"
}
Can someone please let me know what's wrong here and how can I fix the issue? I have added the following dependency within my pom.xml:
<dependencies>
<dependency>
<groupId>org.project1.com</groupId>
<artifactId>project1</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-config-yaml</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-jib</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
</dependency>
</dependencies>
I think y need to add this dependency to get your rest endpoint work otherwise y will get an error invalid MediaType from the resteasy library
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
When you add the dependency, Your endpoint function will be called and you will get 400 (Bad request) and the details of the invalid constraints returned in the response.
I am following this tutorial:
https://www.baeldung.com/spring-boot-embedded-mongodb
Only dot 1,2,3
I need insert and check new registers in my mongoDB embebed.
this is my pom:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.1.1.RELEASE</version><!--$NO-MVN-MAN-VER$ -->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
It is my test.java:
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import com.batch.DesarrolloBatch.model.Documento;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject;
#DataMongoTest
public class TestApplicationConfiguration {
#Test
public void test(#Autowired MongoTemplate mongoTemplate) {
// given
DBObject objectToSave = BasicDBObjectBuilder.start()
.add("_id", "999999999999")
.get();
// when
mongoTemplate.save(objectToSave, "collection");
List<Documento> list = mongoTemplate.findAll(Documento.class, "collection");
System.out.println("size " + list.size());
// then
assertThat(mongoTemplate.findAll(Documento.class, "collection")).extracting("_id")
.containsOnly("999999999999");
}
}
I am trying insert a new Documento with attribute _id value= 99999999
But this code failed, so, I am trying see the size my List for know if I insert success...
I get this error:
java.lang.Exception: Method test should have no parameters
at org.junit.runners.model.FrameworkMethod.validatePublicVoidNoArg(FrameworkMethod.java:76)
at org.junit.runners.ParentRunner.validatePublicVoidNoArgMethods(ParentRunner.java:155)
at org.junit.runners.BlockJUnit4ClassRunner.validateTestMethods(BlockJUnit4ClassRunner.java:208)
at org.junit.runners.BlockJUnit4ClassRunner.validateInstanceMethods(BlockJUnit4ClassRunner.java:188)
at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:128)
at org.junit.runners.ParentRunner.validate(ParentRunner.java:416)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:84)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:65)
at org.junit.internal.builders.JUnit4Builder.runnerForClass(JUnit4Builder.java:10)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createUnfilteredTest(JUnit4TestLoader.java:87)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:73)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:46)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:522)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
I am new in Junit, mongodb ... I only want use mongoDB embebed and insert and check my bbdd .... thanks...
You forgot an annotation on the class level: #ExtendWith(SpringExtension.class)
#DataMongoTest
#ExtendWith(SpringExtension.class)
public class TestApplicationConfiguration {
#Test
public void test(#Autowired MongoTemplate mongoTemplate) {
// your test code
}
}
Please read the tutorial carefully.
Here is the link to the GitHub Repo where you can find the pom.xml and all the source code as well:
https://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-boot-persistence-mongodb
Using the information provided below can you answer the following questions:
What container provider supports org.apache.cxf.jaxrs.JAXRSServerFactoryBean so that I may add my application using org.glassfish.jersey.server.ContainerFactory when creating an end point?
What is wrong with the below application that causes (JAXRSServerFactoryBean)RuntimeDelegate.getInstance().createEndpoint(app, JAXRSServerFactoryBean.class); to throw an illegal argument exception?
I am attempting to deploy a JAX-RS application that uses annotations (no web.xml) to system that uses a Java Application Manager (it is a proprietary system that has ported over some application manager libraries but I am not sure what those are due to little supporting documentation around it).
At a high level I have a Java application that uses JAX-RS annotations, such as ApplicationPath, Path, Produces/Consumes, and JsonProperty, to attempt to create an endpoint on a "application server". I say "application server" because I have no documentation around this system so I am just going to call it that. When attempting to start the application I get the following exception:
java.lang.IllegalArgumentException: No container provider supports the type class org.apache.cxf.jaxrs.JAXRSServerFactoryBean
at org.glassfish.jersey.server.ContainerFactory.createContainer(ContainerFactory.java:64)
at org.glassfish.jersey.server.internal.RuntimeDelegateImpl.createEndpoint(RuntimeDelegateImpl.java:47)
at com.app.Server.startServer(Server.java:182)
I have researched the java.lang.IllegalArgumentException thrown by the org.glassfish.jersey.server.internal.RuntimeDelegateImpl.createEndpoint function. I am not sure why it would do this because on the cover it appears like the application class is annotated correctly and extends Application.
I was able to look at the Server's class code and here is what is being done:
Server Code
Here a snippet portion of com.app.Server.startServer(Server.java:182) code, I cannot alter this code:
inside of startServer...
Application app = (Application) Class.forName("com.app.MyApplication").newInstance();
JAXRSServerFactoryBean jaxrsServerFactory = (JAXRSServerFactoryBean)RuntimeDelegate.getInstance().createEndpoint(app, JAXRSServerFactoryBean.class);
Now my code:
Application Code
MyApplication
package com.app;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import com.app.services.ServiceOne;
#ApplicationPath("base/path")
public class MyApplication extends Application {
public MyApplication() {
System.out.println(Long.toString(System.nanoTime()) + " " + this.getClass().getName() + " constructor called...");
}
/* (non-Javadoc)
* #see javax.ws.rs.core.Application#getClasses()
*/
#Override
public Set<Class<?>> getClasses() {
System.out.println(Long.toString(System.nanoTime()) + " " + this.getClass().getName() + " getClasses() method called...");
Set<Class<?>> classes = new HashSet<>();
classes.add(ServiceOne.class);
return classes;
}
}
My Application's Services
package com.app.services.ServiceOne;
import java.util.ArrayList;
import javax.ws.rs.Consumes;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
// pretend the model imports are here...
#Path("serviceOne")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class ServiceOne {
#PUT
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public ResponseObject performService(InputObject body) throws NotFoundException {
// do whatever to get result and send...
}
}
Pom.xml Plugins and Dependencies
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-jdk-http</artifactId>
<version>2.28-RC4</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>2.28-RC4</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.28-RC4</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.28-RC4</version>
</dependency>
</dependencies>
Thanks again for your help!
I figured out the answer to my question.
The system I was attempting to deploy my application to already had jar files installed on the system in various directories.
I updated my application to include those jar files. This was done by updating a descriptor that I use to deploy the application to the system.
Then I and set the scope of certain dependencies in my pom.xml to <scope>provided</scope> so that when the application was packaged by maven, those dependencies would not be included in the final jar.
Below is an example:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-jdk-http</artifactId>
<version>2.28-RC4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>2.28-RC4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.28-RC4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.28-RC4</version>
<scope>provided</scope>
</dependency>
</dependencies>
This was fixed in my side by excluding jersey-server which has its own META-INF/services/javax.ws.rs.ext.RuntimeDelegate (see RuntimeDelegate.JAXRS_RUNTIME_DELEGATE_PROPERTY), hence preventing the proper loading of org.apache.cxf.jaxrs.impl.RuntimeDelegateImpl. In my case, jersey-server was brought transitively by hadoop-mapreduce-client-core:
<dependency>
<groupId>XXX</groupId>
<artifactId>YYY</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
</exclusion>
</exclusions>
</dependency>
Netty server instantiation in Arjen Poutsma's blog post and Josh Long's video example is done by creating an reactor.ipc.netty.http.HttpServer instance and then calling it's start or startAndAwait method with an ReactorHttpHandlerAdapter instance as an argument.
However the API seems to have changed as now start and startAndAwait methods now expect a lambda with the following signature:
java.util.function.Function<? super reactor.ipc.netty.http.HttpChannel,? extends org.reactivestreams.Publisher<java.lang.Void>>
Project dependencies and their versions are the same as in Arjen Poutsma's example project
<dependency>
<groupId>org.reactivestreams</groupId>
<artifactId>reactive-streams</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>io.projectreactor.ipc</groupId>
<artifactId>reactor-netty</artifactId>
<version>0.5.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web-reactive</artifactId>
<version>5.0.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.2</version>
</dependency>
What is the new/proper way of instantiating a netty server with spring reactor support?
The recommended way to set up project for now is to use http://start.spring.io/ as Josh Long suggests in his video. This is because spring reactive is only release candidate now and we need compatible versions to run samples.This is achieved via adding this piece to code:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot.experimental</groupId>
<artifactId>spring-boot-dependencies-web-reactive</artifactId>
<version>0.1.0.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
According your question about HttpServer interface change, the minimal working example is the following:
import org.reactivestreams.Publisher;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.RouterFunction;
import org.springframework.web.reactive.function.ServerRequest;
import org.springframework.web.reactive.function.ServerResponse;
import reactor.core.publisher.Mono;
import reactor.ipc.netty.http.server.HttpServer;
import java.io.IOException;
import static org.springframework.web.reactive.function.RequestPredicates.GET;
import static org.springframework.web.reactive.function.RouterFunctions.route;
import static org.springframework.web.reactive.function.RouterFunctions.toHttpHandler;
public class FunctionalReactiveServer {
public static final String HOST = "localhost";
public static final int PORT = 8080;
public static void main(String[] args) throws InterruptedException, IOException {
RouterFunction<?> route = route(GET("/sayHello"), FunctionalReactiveServer::sayHelloHandler);
HttpHandler httpHandler = toHttpHandler(route);
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
HttpServer server = HttpServer.create(HOST, PORT);
server.newHandler(adapter).block();
System.out.println("Press ENTER to exit.");
System.in.read();
}
public static ServerResponse<Publisher<String>> sayHelloHandler(ServerRequest request) {
return ServerResponse.ok().body(Mono.just("Hello!"), String.class);
}
}