0

I'm using dropwizard (jersey, jackson) to create a REST API and have stumbled upon some problems I can't seem to find the answer to. I would like to build an sql query based on a json file. This would be done via a map (criteria, value). I have some problems realising this:

  • Calling the DAO method getUserByCriteria(Map/JSONObject) will give me this type of error: UnsupportedOperationException: No type parameters found for erased type 'interface java.util.Map[K, V]'. To bind a generic type, prefer using bindByType. OR a "No Argument factory" error which I can't seem to reproduce atm

Code:

UserResource:

@POST
@Path("/list")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public List<User> getUser(@Auth UserToken token, JSONObject json) {
return userDAO.getUserByCriteria(json);
}

UserDao:

List<User> getInvoiceByCriteria(@Bind("json") JSONObject json);
  • When I do get this to work, how would I go about it? My code looks like this (can't seem to get the code block formatted for this one):

    @SqlQuery("SELECT * FROM user LIMIT 10")

    @RegisterRowMapper(UserMapper.class)

    List getUserByCriteria(@Bind("json") Map json);

And I would like to make it do something like this:

@SqlQuery("SELECT * FROM user WHERE crit1 = :crit1 AND crit2 = :crit2 LIMIT 10")
@RegisterRowMapper(UserMapper.class)
List<User> getUserByCriteria(@Bind("json") Map json){
//EXTRACT VALUES OF MAP HERE
//
};

I realise this is a pretty vague question. Problem is I'm a pretty big noob on this REST stuff and the problems I encounter aren't that common (or I'm searching for the wrong things). Any help/insight is greatly appreciated!

Xtra question regarding http/rest: I feel like this should be a GET request instead of a POST, but my Advanced Rest Client doesn't allow for a body in the GET request. I found online that this is usually not done, but allowed. Is using POST ok here?

ArthurP
  • 117
  • 1
  • 2
  • 10
  • It looks like you're trying to build a query dynamically using JDBI. See this [question](https://stackoverflow.com/questions/36359708/jdbi-how-can-i-dynamically-create-a-where-clause-while-preventing-sql-injection) and related answers. – spinlok Mar 15 '18 at 04:52

2 Answers2

2

Here is a simple example of a DAO interface using a Mapper :

@RegisterMapper(EmployeeMapper.class)
public interface EmployeeDao {

@SqlQuery("select * from employee;")
public List<Employee> getEmployees();

@SqlQuery("select * from employee where id = :id")
public Employee getEmployee(@Bind("id") final int id);

@SqlUpdate("insert into employee(name, department, salary) values(:name, :department, :salary)")
void createEmployee(@BindBean final Employee employee);

@SqlUpdate("update employee set name = coalesce(:name, name), " +
        " department = coalesce(:department, department), salary = coalesce(:salary, salary)" +
        " where id = :id")
void editEmployee(@BindBean final Employee employee);

@SqlUpdate("delete from employee where id = :id")
int deleteEmployee(@Bind("id") final int id);

@SqlQuery("select last_insert_id();")
public int lastInsertId();
}

Here is the Employee Mapper Class used above:

public class EmployeeMapper implements ResultSetMapper<Employee> {
private static final String ID = "id";
private static final String NAME = "name";
private static final String DEPARTMENT = "department";
private static final String SALARY = "salary";

public Employee map(int i, ResultSet resultSet, StatementContext statementContext)
        throws SQLException {
    Employee employee = new Employee(resultSet.getString(NAME), resultSet.getString(DEPARTMENT),resultSet.getInt(SALARY));
    employee.setId(resultSet.getInt(ID));
    return employee;
}
}

I have explained how to use JDBI, create REST APIs in Dropwizard in simple steps in a blog post and there is also a sample working application that I have created on GitHub. Please check: http://softwaredevelopercentral.blogspot.com/2017/08/dropwizard-mysql-integration-tutorial.html

1

I will answer first to your Xtra question :

The objective of the GET is to retrieve data with the URI and params sent in the URI. There is a difference b/w can or should. It's the same with Body with GET, you can send the body with GET but then you are not following the HTTP Guidelines also the purpose of GET and POST are mixed. <Refer Here> and <here>

Now in your question. You are sending JSONObject json in

public List<User> getUser(@Auth UserToken token, JSONObject json) {
return userDAO.getUserByCriteria(json);
}

but your are matching with Map. Map is basically entertains TypeErasure < which means while compiling the code your collection's generic will be replaced by bind objects of this> You can rather Insert type casts if necessary to preserve type safety. Also you can use something like this

List<User> getInvoiceByCriteria(@Bind("json") Map<K extends String , V extends MyObject> json);
Community
  • 1
  • 1
Sagar Kharab
  • 369
  • 2
  • 18
  • Ok, so POST is fine here if I understand correctly? Also: I made it so that they're both a JSONObject now (which is how it originally was in my code, tried a lot of things & this got mixed up). So this isn't the problem. Thanks for the reply! – ArthurP Mar 14 '18 at 10:30
  • if you have any body in the request then yes `Post` is correct. Also if u think this helped you and find it useful please upvote or accept. I need 50 to comment everywhere. – Sagar Kharab Mar 14 '18 at 10:48