Home > Blockchain >  Java REST API Getting Error when sending GET Request, but works on POST
Java REST API Getting Error when sending GET Request, but works on POST

Time:09-07

I have a REST API linked with a Java app that is connected to a database using JDBC that I am currently testing through the Swagger UI.

Sending post Requests work completely fine, and sending GET requests when the table for a given type is empty also seems to return a normal response, however once I send a GET request when there is data in the table, I get the following error.

GET /api/user 500 Server Error
java.lang.reflect.UndeclaredThrowableException: null
    at jdk.proxy2/jdk.proxy2.$Proxy16.getPersons(Unknown Source)
    at module.PersonModule.lambda$new$41b6884b$1(PersonModule.java:23)
    at io.jooby.internal.handler.DefaultHandler.apply(DefaultHandler.java:23)
    at io.jooby.internal.handler.WorkerHandler.lambda$apply$0(WorkerHandler.java:23)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NoSuchMethodException: no such constructor: domain.Person.<init>()void/newInvokeSpecial
    at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:974)
    at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1117)
    at java.base/java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:3649)
    at java.base/java.lang.invoke.MethodHandles$Lookup.findConstructor(MethodHandles.java:2750)
    at org.jdbi.v3.core.mapper.reflect.internal.BeanPropertiesFactory$BeanPojoProperties$PropertiesHolder.<init>(BeanPropertiesFactory.java:202)
    at org.jdbi.v3.core.config.JdbiCaches.lambda$declare$0(JdbiCaches.java:49)
    at org.jdbi.v3.core.config.JdbiCaches$1.lambda$get$1(JdbiCaches.java:63)
    at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
    at org.jdbi.v3.core.config.JdbiCaches$1.get(JdbiCaches.java:63)
    at org.jdbi.v3.core.mapper.reflect.internal.BeanPropertiesFactory$BeanPojoProperties.getProperties(BeanPropertiesFactory.java:81)
    at org.jdbi.v3.core.mapper.reflect.internal.PojoMapper.specialize0(PojoMapper.java:99)
    at org.jdbi.v3.core.mapper.reflect.internal.PojoMapper.specialize(PojoMapper.java:80)
    at org.jdbi.v3.core.result.ResultSetResultIterator.<init>(ResultSetResultIterator.java:38)
    at org.jdbi.v3.core.result.ResultIterable.lambda$of$0(ResultIterable.java:54)
    at org.jdbi.v3.core.result.ResultIterable.stream(ResultIterable.java:228)
    at org.jdbi.v3.core.result.ResultIterable.collect(ResultIterable.java:284)
    at org.jdbi.v3.sqlobject.statement.internal.ResultReturner$CollectedResultReturner.mappedResult(ResultReturner.java:275)
    at org.jdbi.v3.sqlobject.statement.internal.SqlQueryHandler.lambda$configureReturner$0(SqlQueryHandler.java:61)
    at org.jdbi.v3.sqlobject.statement.internal.CustomizingStatementHandler.invoke(CustomizingStatementHandler.java:178)
    at org.jdbi.v3.sqlobject.statement.internal.SqlQueryHandler.invoke(SqlQueryHandler.java:27)
    at org.jdbi.v3.sqlobject.internal.SqlObjectInitData$1.lambda$invoke$0(SqlObjectInitData.java:132)
    at org.jdbi.v3.core.internal.Invocations.invokeWith(Invocations.java:44)
    at org.jdbi.v3.core.internal.Invocations.invokeWith(Invocations.java:26)
    at org.jdbi.v3.core.LazyHandleSupplier.lambda$invokeInContext$1(LazyHandleSupplier.java:77)
    at org.jdbi.v3.core.internal.Invocations.invokeWith(Invocations.java:44)
    at org.jdbi.v3.core.internal.Invocations.invokeWith(Invocations.java:26)
    at org.jdbi.v3.core.LazyHandleSupplier.invokeInContext(LazyHandleSupplier.java:76)
    at org.jdbi.v3.sqlobject.internal.SqlObjectInitData$1.call(SqlObjectInitData.java:138)
    at org.jdbi.v3.sqlobject.internal.SqlObjectInitData$1.invoke(SqlObjectInitData.java:132)
    at org.jdbi.v3.sqlobject.SqlObjectFactory.lambda$attach$2(SqlObjectFactory.java:110)
    at org.jdbi.v3.core.internal.OnDemandExtensions.lambda$invoke$5(OnDemandExtensions.java:98)
    at org.jdbi.v3.core.internal.exceptions.Unchecked.lambda$function$4(Unchecked.java:76)
    at org.jdbi.v3.core.internal.OnDemandExtensions.invoke(OnDemandExtensions.java:98)
    at org.jdbi.v3.core.internal.OnDemandExtensions.lambda$createProxy$2(OnDemandExtensions.java:82)
    at org.jdbi.v3.core.Jdbi.callWithExtension(Jdbi.java:476)
    at org.jdbi.v3.core.Jdbi.withExtension(Jdbi.java:463)
    at org.jdbi.v3.core.internal.OnDemandExtensions.lambda$createProxy$3(OnDemandExtensions.java:82)
    ... 8 common frames omitted
Caused by: java.lang.NoSuchMethodError: domain.Person: method 'void <init>()' not found
    at java.base/java.lang.invoke.MethodHandleNatives.resolve(Native Method)
    at java.base/java.lang.invoke.MemberName$Factory.resolve(MemberName.java:1085)
    at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1114)
    ... 43 common frames omitted

Line 23 of PersonModule which is stated as throwing the error has the following code

 public PersonModule(PersonDAO dao){
        
        path("/api/user", () -> {
            get("", ctx -> {
                return dao.getPersons();
            });
            
            post("", ctx -> {
                Person person = ctx.body().to(Person.class);
                if (dao.getPerson(person.getEmail()) == null) {
                    dao.savePerson(person);
                    return ctx.send(StatusCode.CREATED);
                } else {
                    return ctx
                            .setResponseCode(StatusCode.UNPROCESSABLE_ENTITY)
                            .render(new ErrorMessage("That email already exists in the system"));
                }
            });
        });

With return dao.getPersons() being line 23

Code for the JDBI for get persons is

    @Override
    @SqlQuery("SELECT * FROM PERSON ORDER BY EMAIL")
    @RegisterBeanMapper(Person.class)
    public Collection<Person> getPersons();

and Person.class has the following code (also includes normal getter and setter methods)

 public Person(Integer personID, String email, String password, String firstName, String lastName, String phone, String mobile, String industry, String bio, String city, Boolean active, String findOut, String role, String notes) {
        this.personID = personID;
        this.email = email;
        this.password = password;
        this.firstName = firstName;
        this.lastName = lastName;
        this.phone = phone;
        this.mobile = mobile;
        this.industry = industry;
        this.bio = bio;
        this.city = city;
        this.active = active;
        this.findOut = findOut;
        this.role = role;
        this.notes = notes;
    }

Could I please get some help identifying what the problem is?

Note : GET requests were tested a little earlier on and seemed to work fine, even with data in the database. Unit tests for the DAO also pass with no errors.

CodePudding user response:

I have found the issue,

I the constructor in my Domain class seemed to be the error, I fixed the error by adding an empty constructor in my Person.class above the current one

public Person(){
        
    }

public Person(Integer personID, String email, String password, String firstName, String lastName, String phone, String mobile, String industry, String bio, Boolean active, String city,  String findOut, String role, String notes) {
        this.personID = personID;
        this.email = email;
        this.password = password;
        this.firstName = firstName;
        this.lastName = lastName;
        this.phone = phone;
        this.mobile = mobile;
        this.industry = industry;
        this.bio = bio;
        this.city = city;
        this.active = active;
        this.findOut = findOut;
        this.role = role;
    }

Now it works fine. If anyone has an explanation for why this is I'd love to know :)

CodePudding user response:

Try actual column names in your SQL query. Instead of this:

SELECT * FROM PERSON ORDER BY EMAIL

Try this:

SELECT PERSONID, EMAIL, PASSWORD,... FROM PERSON ORDER BY EMAIL

CodePudding user response:

You should get the essence from your error outputs.

It relates lambda code inside a constructor INIT , no such method getPersons

WITH the problem the code should have an exception wrapped around or added onto the constructor declaration start , supposedly at least for the get request code e.g. throws ServletException and UnavailableException

GET /api/user 500 Server Error
java.lang.reflect.UndeclaredThrowableException: null
    at jdk.proxy2/jdk.proxy2.$Proxy16.getPersons(Unknown Source)
    at module.PersonModule.lambda$new$41b6884b$1(PersonModule.java:23)

    path("/api/user", () -> {
                get("", ctx -> {
                    return dao.getPersons();
                });
            
            

The following references an odd action you take of getting all the persons onto a Collection object with getPersons method , but you do nothing with it except return it i presume as "ctx" and unfortunately you did not actually say the type of object ctx is.

@Override
@SqlQuery("SELECT * FROM PERSON ORDER BY EMAIL")
@RegisterBeanMapper(Person.class)
public Collection<Person> getPersons();

Somehow ALL the required constructor parameters for Person class are sent in a post , but in get no Person class is made in the code which i find odd that it did not continue to throw errors whether you gave it a no-arguments constructor as an abstract class has, but wonder if it is treated as an abstract class, the more normal way is to make a DTO Data Transfer Object template and
entity in between the DAO Data Access Object class with interfaces to call through. Moreover, the getPersons collection does not appear to have any use, so why the massive query retrieval.

  • Related