Reputation: 16055
After few years I got back to Java to try to implement RESTful WS using Java. I have found plenty of tutorials and articles about implementing it using Spring and it's Spring boot extension on top of Maven. After first problems with setting all up I finally have a WS that is running and is accessible (e.g. from CLI using curl
).
Unfortunately I am getting java.lang.IllegalArgumentException
exceptions, with these two messages:
java.lang.IllegalArgumentException: Parameter with that position [1] did not exist
and
java.lang.IllegalArgumentException: Parameter with that name [cart_id] did not exist
Here's my shortened Entity
class:
@Entity
@Table(name = "cart", catalog = "table1", schema = "")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "Cart.findAll", query = "SELECT c FROM Cart c"),
@NamedQuery(name = "Cart.findByCartId", query = "SELECT c FROM Cart c WHERE c.cartId = :cartId"),
@NamedQuery(name = "Cart.findByBarcode", query = "SELECT c FROM Cart c WHERE c.barcode = :barcode"),
@NamedQuery(name = "Cart.findByCartTypeId", query = "SELECT c FROM Cart c WHERE c.cartTypeId = :cartTypeId"),
@NamedQuery(name = "Cart.findByCartStyleId", query = "SELECT c FROM Cart c WHERE c.cartStyleId = :cartStyleId"),
@NamedQuery(name = "Cart.findByCartName", query = "SELECT c FROM Cart c WHERE c.cartName = :cartName"),
@NamedQuery(name = "Cart.findByNotificationId", query = "SELECT c FROM Cart c WHERE c.notificationId = :notificationId"),
@NamedQuery(name = "Cart.findByCartContentId", query = "SELECT c FROM Cart c WHERE c.cartContentId = :cartContentId"),
@NamedQuery(name = "Cart.findByStationId", query = "SELECT c FROM Cart c WHERE c.stationId = :stationId"),
@NamedQuery(name = "Cart.findByUserId", query = "SELECT c FROM Cart c WHERE c.userId = :userId"),
@NamedQuery(name = "Cart.findByStatus", query = "SELECT c FROM Cart c WHERE c.status = :status")})
public class Cart implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Basic(optional = false)
@Column(name = "cart_id")
private Long cartId;
@Size(max = 50)
private String barcode;
@Column(name = "notification_id")
private Integer notificationId;
// other properties, getters and setters follow ...
}
Here the repository:
@RepositoryRestResource
public interface CartDAO extends CrudRepository<Cart, Long> {
/**
* Returns cart by it's ID.
* @param cartId
* @return Cart
*/
public Cart findByCartId(@Param("cart_id") Long cartId);
/**
* Returns cart by it's barcode (EAN).
* @param barcode
* @return Cart
*/
public Cart findByBarcode(String barcode);
/**
* Returns all the carts belonging to notification (by notification ID).
* @param notificationId
* @return List of Carts
*/
public List<Cart> findByNotificationId(@Param("notification_id") Integer notificationId);
}
And here's the controller:
@RestController
@RequestMapping("/carts")
public class CartController {
@Autowired
private CartDAO cartDao;
@RequestMapping(value="/id/{cartId}", method = RequestMethod.GET)
public Cart getCartById(@PathVariable Long cartId) {
return cartDao.findByCartId(cartId);
// return cartDao.findOne(cartId);
}
@RequestMapping(value="/ean/{barcode}", method = RequestMethod.GET)
public Cart getCartByBarcode(@PathVariable String barcode) {
return cartDao.findByBarcode(barcode);
}
@RequestMapping(value="/notification/{notificationId}", method = RequestMethod.GET)
public List<Cart> getCartByNotification(@PathVariable Integer notificationId) {
return cartDao.findByNotificationId(notificationId);
}
}
If I call the WS with cmd curl -g localhost:8080/carts/id/1
or curl -g localhost:8080/carts/notification/1
I got the exception with the second msg (for name [cart_id]
or [notification_id]
). If I call the cmd curl -g localhost:8080/carts/ean/2550000017884
I got the exception with the first msg (for position [1]
).
The DB table looks like:
cart
===========================================
cart_id INT (PK, auto_increment)
notification_id INT (FK)
barcode VARCHAR(13) (NOT NULL, UNIQUE)
...
However if I switch comment for the two lines in CartController.getCartById()
(i.e. let return cartDao.findOne(cartId);
to be invoked instead of return cartDao.findByCartId(cartId);
), then I finally can see a valid response without exception.
But what am I doing wrong here? Obviously I am missing something (and all the tutorials as well).
PS: I have created all the entities using the persistance unit
- I have let the PU to connect to my DB and to create all the entities for me. I liked to work this way back in the days as PU can handle very quickly changes on both sides and mirror them on the other. With the help of PU I also have lot of @NamedQueries
which could be of help but since all the spring-boot tutorials are working with JPA repository I don't know either how to call those named queries from Persistence...
EDIT: adding the dependencies part of my pom.xml
:
<dependencies>
<!-- Get the dependencies of a web application -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- DB -->
<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-rest</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<type>jar</type>
</dependency>
</dependencies>
Upvotes: 1
Views: 549
Reputation: 124441
The fact that the @Param
works (and not giving an error) indicates that a pre defined query is executed. Without a query the @Param
would fail.
Spring Data uses a strategy to determine which query to execute by default it uses CREATE_IF_NOT_FOUND
lookup strategy. It first tries to find a pre-defined query, this can be either a @Query
on the method or a @NamedQuery
for JPA (in the latter case it is looking for a <entity-name>.<method-name>
named query). If neither of these applies it will create a query based on the method.
In your case you have a named query with the name Cart.findByCartId
(and the same applies to the other methods as well). Spring Data detects this query and will execute it. Due to your @Param
it tries to find a parameter named cart_id
but the name is actually cartId
(see the named query).
To solve your issue either
1. Fix the @Param
annotations in your method to point to the correct parameter names
2. Remove the @Param
and @NamedQuery
s
3. Switch Spring Data JPA to the CREATE
lookup strategy and remove the @Param
.
Upvotes: 2