I am new to Spring and MapStruct. I am having issues with conversion from Page to List. I used the MapStruct mapper in the service. I need to fetch all products from DB, then convert to ProductResponse using MapStruct mapper and then return PagedResponse object but the following error appears:
java.lang.ClassCastException: org.springframework.data.domain.PageImpl cannot be cast to java.util.List
at org.walana.GP.service.ProductService.getAll(ProductService.java:67) ~[classes/:na]
at org.walana.GP.controller.ProductController.getAll(ProductController.java:40)
ReplaceNumber
#Entity
#Table(name = "replace_numbers")
public class ReplaceNumber extends UserDateAudit
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank
#Size(max = 20)
private String partNumber;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "product_id", nullable = false)
private Product product;
public ReplaceNumber() {}
public ReplaceNumber(String partNumber)
{
this.partNumber = partNumber;
}
}
ReplaceNumberResponse
public class ReplaceNumberResponse
{
private Long id;
private String partNumber;
}
Product
#Entity
#Table(name = "products", indexes = {#Index(name= "part_number_index", columnList = "part_number", unique = true)})
public class Product extends UserDateAudit
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank
#Column(name = "part_number", nullable = false)
#Size(max = 20)
private String partNumber;
#NotBlank
#Size(max = 255)
private String description;
#OneToMany(
mappedBy = "product",
cascade = CascadeType.ALL,
fetch = FetchType.EAGER,
orphanRemoval = true
)
#Fetch(FetchMode.SELECT)
private List<ReplaceNumber> replaceNumbers = new ArrayList<>();
#ManyToOne
#JoinColumn(name = "product_manufacturer_id", referencedColumnName = "id")
private ProductManufacturer manufacturer;
#ManyToOne
#JoinColumn(name = "product_model_id", referencedColumnName = "id")
private ProductModel model;
#ManyToOne
#JoinColumn(name = "product_category_id", referencedColumnName = "id")
private ProductCategory category;
#Column(name = "cost", nullable = false)
#DecimalMin(message = "Cost should be greater than 1", value = "1")
private float cost;
#Column(name = "price", nullable = false)
#DecimalMin(message = "Price should be greater than 0", value = "0")
private float price;
}
ProductResponse
public class ProductResponse
{
private Long id;
private String partNumber;
private String description;
private List<ReplaceNumberResponse> replaceNumberResponses;
private ProductManufacturerResponse manufacturer;
private ProductModelResponse model;
private ProductCategoryResponse category;
private float cost;
private float price;
}
ProductMapper
#Mapper(componentModel = "spring")
public interface ProductMapper
{
ProductResponse toProductResponse(Product product);
List<ProductResponse> toProductResponses(List<Product> products);
Product toProduct(ProductResponse productResponse);
}
PagedResponse
public class PagedResponse<T>
{
private List<T> content;
private int page;
private int size;
private long totalElements;
private int totalPages;
private boolean last;
public PagedResponse() {
}
public PagedResponse(List<T> content, int page, int size, long totalElements, int totalPages, boolean last) {
this.content = content;
this.page = page;
this.size = size;
this.totalElements = totalElements;
this.totalPages = totalPages;
this.last = last;
}
}
ProductService
#Service
public class ProductService
{
#Autowired
ProductRepository productRepository;
#Autowired
ProductMapper productMapper;
public PagedResponse<ProductResponse> getAll(UserPrincipal currentUser, int page, int size)
{
Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, "createdAt");
Page<Product> products = productRepository.findAll(pageable);
if (products.getNumberOfElements() == 0)
{
return new PagedResponse<>(Collections.emptyList(), products.getNumber(),
products.getSize(), products.getTotalElements(), products.getTotalPages(), products.isLast());
}
List<ProductResponse> productResponses = productMapper.toProductResponses((List<Product>) products);
return new PagedResponse<>(productResponses, products.getNumber(),
products.getSize(), products.getTotalElements(), products.getTotalPages(), products.isLast());
}
}
ProductController
#RestController
#RequestMapping("/api/products")
public class ProductController
{
#Autowired
private ProductService productService;
private static final Logger logger = LoggerFactory.getLogger(ProductController.class);
#GetMapping
public PagedResponse<ProductResponse> getAll(#CurrentUser UserPrincipal currentUser,
#RequestParam(value = "page", defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) int page,
#RequestParam(value = "size", defaultValue = AppConstants.DEFAULT_PAGE_SIZE) int size)
{
return productService.getAll(currentUser, page, size);
}
}
Replace
productMapper.toProductResponses((List<Product>) products)
with
productMapper.toProductResponses(products.getContent())
Related
I 'm new in spring and hibernate. i have a sample project that not work properly. when i try to save new order from user, i get no error or exceprion, but record not inserted into database.
here my code
strong textStoreController.java
#Autowired
OrderService orderService;
#SuppressWarnings("unchecked")
#RequestMapping(value = "/store/addorder", method = RequestMethod.GET)
public ModelAndView addOrder(HttpSession session) {
ModelAndView model = new ModelAndView();
// create list of products that we have to add in orders
List<CartItem> items = (List<CartItem>) session.getAttribute("cart");
Set<CartItem> itemsSet = new HashSet<CartItem>();
// new order generated and setter methods invoke
Orders order = new Orders(itemsSet);
Date d = new Date();
Date delivery = StoreUtils.deliveryDate(d, 3);
order.setOrderDate(d);
order.setDeliveryDate(delivery);
order.setItems(itemsSet);
for (CartItem cartItem : items) {
itemsSet.add(cartItem);
}
String addOrders = orderService.addOrders(order);
System.err.println("new order add status " + addOrders + "-------------");
// change product quantity after adding new order
if (!addOrders.toLowerCase().contains("error")) {
for (int i = 0; i < items.size(); i++) {
Integer qSale = items.get(i).getQuantity() * (-1);
productService.rechargeProduct(items.get(i).getProduct(), qSale);
}
model.setViewName("successorder");
model.addObject("order", order);
model.addObject("message", addOrders);
session.setAttribute("cart", null);
} else {
session.setAttribute("error", addOrders);
model.setViewName("redirect:/addtocartlist");
}
return model;
}
Orders.java
#Entity
#Table(name = "orders")
public class Orders implements Serializable {
private static final long serialVersionUID = -3672662224925418969L;
#Id
#Column(name = "orderid", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#DateTimeFormat(pattern = "yyyy-mm-dd")
#Column(name = "orderDate", nullable = false)
private Date orderDate;
#DateTimeFormat(pattern = "yyyy-mm-dd")
#Column(name = "delivery", nullable = false)
private Date deliveryDate;
#Column(name = "success", nullable = true, columnDefinition = "tinyint(1) default 0")
private boolean success;
#Column(name = "cancel", nullable = true, columnDefinition = "tinyint(1) default 0")
private boolean canceled;
#Column(name = "cause", nullable = true)
private String cancelCause;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable(name = "ORDERS_ITEMS", joinColumns = { #JoinColumn(name = "orderid") }, inverseJoinColumns = {
#JoinColumn(name = "item_id") })
private Set<CartItem> items = new HashSet<CartItem>(0);
//setters and getters
}
CartItem.java
#Entity
#Table(name = "items")
public class CartItem implements Serializable {
private static final long serialVersionUID = 7968604053015663078L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "item_id", nullable = false)
private Long id;
#Column(name = "quantity", nullable = false, columnDefinition = "int(11) default 1")
private Integer quantity;
#Column(name = "totalprice", nullable = false)
private BigDecimal totalprice;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "prd_id", nullable = false)
private Product product;
//setters and getters
}
Product.java
#Entity
#Table(name = "products")
public class Product implements Serializable {
private static final long serialVersionUID = -7738539408628995177L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "prd_id")
private Long id;
#Column(name = "full_name", nullable = false)
private String fullName;
#Column(name = "seller_name")
private String seller;
#Column(name = "company_name", nullable = false)
private String companyName;
#Column(name = "created_date")
#DateTimeFormat(pattern = "yyyy-mm-dd")
private Date createdDate;
#Column(name = "expiry_date")
#DateTimeFormat(pattern = "yyyy-mm-dd")
private Date expiryDate;
#Column(name = "insert_date")
#DateTimeFormat(pattern = "yyyy-mm-dd")
private Date insertDate;
#Column(name = "likes", nullable = true)
private Integer likeCount;
#Column(name = "quantity", nullable = true)
private Integer quantity;
#Column(name = "price", nullable = false)
private BigDecimal price;
#Column(name = "category", nullable = false)
private String category;
#Column(name = "description", nullable = true)
private String description;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "product")
private Set<CartItem> items;
//setters and getters
}
and finally here is my doa implementation code
OrdersDaoImpl.java
#Repository("ordersDao")
public class OrdersDaoImpl implements OrdersDao {
#Autowired
SessionFactory sessionFactory;
protected Session session() {
try {
return sessionFactory.getCurrentSession();
} catch (HibernateException e) {
return sessionFactory.openSession();
}
}
public String addOrders(Orders orders) {
String result = "";
try {
session().save(orders);
result = "success";
} catch (Exception e) {
if (e.getMessage().toLowerCase().contains("duplicate"))
result = "error this order already was exist";
else
result = "error " + e.getMessage();
System.err.println(result);
} finally {
session().clear();
}
return result;
}
}
when i try to add new order i get no exception. why my service not work?
i have another controller in my project, that manage users. in that controller and dao implementation add and remove user working properly.
i think i have logic error in my code for one to many and many to many. please help me to overcome this fail.
I am not able to save the following entity. I would like to select Lab when I trying to save Server.
#Entity
#Getter
#Setter
public class Lab {
#Id
#GeneratedValue
#Column(name = "ID")
private Long id;
#NotNull
#Column(name = "LAB_NAME")
private String labName;
#NotNull
#Column(name = "LAB_PRIME")
private String labPrime;
#NotNull
#Column(name = "LAB_SERVICE_IP", nullable = false)
private String serviceIp;
#Column(name = "LAB_OWNER", nullable = false)
#Enumerated(EnumType.STRING)
private LabOwner labOwner;
#Column(name = "LAB_RELEASE")
#Enumerated(EnumType.STRING)
private LabRelease labRelease;
#JsonIgnore
#OneToMany(fetch = FetchType.EAGER)
private Set<Server> servers;
public Lab() {
}
public Lab(String labName, String labPrime, String serviceIp, LabOwner labOwner, LabRelease labRelease, Set<Server> servers) {
this.labName = labName;
this.labPrime = labPrime;
this.serviceIp = serviceIp;
this.labOwner = labOwner;
this.labRelease = labRelease;
this.servers = servers;
}
}
Repositories:
public interface LabRepository extends JpaRepository<Lab, Long> {
}
public interface ServerRepository extends JpaRepository<Server, Long> {
}
Server Entitiy;
#Entity
#Getter
#Setter
public class Server {
#Id
#GeneratedValue
#Column(name = "ID")
private Long id;
#NotNull
#Column(name = "LOGICAL_IP")
private String logicalIp;
#NotNull
#Column(name = "INSTANCE_TYPE")
private String instanceType;
#NotNull
#Column(name = "HOST_NAME", nullable = false)
private String hostName;
#NotNull
#Column(name = "HDWR_TYPE", nullable = false)
private String hardwareType;
#NotNull
#Column(name = "A2_TYPE", nullable = false)
private String a2Type;
#ManyToOne(fetch = FetchType.LAZY)
private Lab lab;
public Server() {
}
public Server(String logicalIp, String instanceType, String hostName, String hardwareType, String a2Type, Lab lab) {
this.logicalIp = logicalIp;
this.instanceType = instanceType;
this.hostName = hostName;
this.hardwareType = hardwareType;
this.a2Type = a2Type;
this.lab = lab;
}
}
Controller:
#RestController
#RequestMapping(value = "services/")
public class GenericController {
#Autowired
LabRepository labRepository;
#Autowired
LabRepository serverRepository;
#RequestMapping(value = "server", method = RequestMethod.POST)
public Server create(#RequestBody Server server) {
return serverRepository.saveAndFlush(server);
}
}
I cannot use serverRepository.saveAndFlush(server). It says that S is not within its bound, should extend Lab .
However, when I extend Lab entitiy, my tables were merged. I would like to 2 seperated tables.
In your controller you are using LabRepository instead of ServerRepository. It should be:
#RestController
#RequestMapping(value = "services/")
public class GenericController {
#Autowired
LabRepository labRepository;
#Autowired
ServerRepository serverRepository;
#RequestMapping(value = "server", method = RequestMethod.POST)
public Server create(#RequestBody Server server) {
return serverRepository.saveAndFlush(server);
}
}
The version for the class Application is getting incremented after the execution of the following statement
Queue queue = queueDao.fetchQueueByApplicationId(application.getApplicationId());
It is a simple fetch query only and it should not increment the version of the call any how. But after above line execution the version is getting incremented unexpectedly for Application class
Could someone please help
Thanks.
Queue.java
#Entity
#Table(name = "queue")
#NamedQuery(name = "queueByApplicationId", query = "SELECT q from Queue q WHERE q.application.applicationId = ?")
public class Queue implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "queue_id", unique = true, nullable = false)
private Long queueId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created", nullable = false, length = 19)
private Date created;
#Column(name = "created_by")
private Long createdBy;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updated", length = 19)
private Date updated;
#Column(name = "updated_by")
private Long updatedBy;
#Version
#Column(name = "version", nullable = false)
private Integer version;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "application_id")
private Application application;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "queue", cascade = { CascadeType.PERSIST, CascadeType.MERGE })
private List<QueueAssignedToRole> queueAssignedToRoles;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "queue", cascade = { CascadeType.PERSIST, CascadeType.MERGE })
private List<QueueAssignedUser> queueAssignedUsers;
getter setter ....
}
Application.java
#Entity
#Table(name = "application")
public class Application implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Long applicationId;
private Integer version;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "application_id", unique = true, nullable = false)
public Long getApplicationId() {
return this.applicationId;
}
public void setApplicationId(Long applicationId) {
this.applicationId = applicationId;
}
#Version
#Column(name = "version", nullable = false)
public Integer getVersion() {
return this.version;
}
public void setVersion(Integer version) {
this.version = version;
}
}
ApplicationQueueDaoImpl.java
#Repository
public class ApplicationQueueDaoImpl extends AbstractDao<Queue> {
private static final Logger LOGGER = LogManager.getLogger(ApplicationQueueDaoImpl.class);
#Override
public Queue fetchQueueByApplicationId(Long applicationId) {
LOGGER.debug("Fetching Queue information for applicationId {}", applicationId);
List<Queue> queues = executeNamedQuery("queueByApplicationId", Queue.class, applicationId);
return CollectionUtils.isEmpty(queues) ? null : queues.get(0);
}
}
AbstractDao.java
protected <T> List<T> executeNamedQuery(String queryName, Class<T> resultType, Object... positionalParams) {
TypedQuery<T> query = entityManager.createNamedQuery(queryName, resultType);
DAOUtils.setPositionalParams(query, positionalParams);
return query.getResultList();
}
I write my first java application to read rss stream and use spring, spring-data, hibernate.
My models.
RssFeed:
#Entity(name = "RssFeed")
#Table(name = "FEED")
#JsonIgnoreProperties({"rssChannel"})
public class RssFeed {
#Id
#GeneratedValue
#Column
private Integer id;
#Column(unique = true)
#Index(name = "title_index")
private String title;
#Column
#URL
private String link;
#Column
private String description;
#Column
private String content;
#Column
#Temporal(TemporalType.TIMESTAMP)
private Date pubDate;
#Column
#Temporal(TemporalType.TIMESTAMP)
private Date updateDate;
#ManyToOne
#JoinColumn(name = "channelId")
private RssChannel rssChannel;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "feed_category",
joinColumns = {#JoinColumn(name = "feed_id", nullable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(name = "category_id", nullable = false, updatable = false)})
private Set<RssCategory> rssCategories = new LinkedHashSet<RssCategory>();
}
RssChannel:
#Entity(name = "RssChannel")
#Table(name = "Channel",
uniqueConstraints = #UniqueConstraint(columnNames = {"link"}))
#JsonIgnoreProperties({"feeds"})
public class RssChannel implements Serializable{
#Id
#GeneratedValue
#Column
private Integer id;
#Column
private String title;
#Column(unique = true)
#org.hibernate.validator.constraints.URL
private String link;
#Column
#org.hibernate.validator.constraints.URL
private String image;
#Column
private String description;
#OneToMany(mappedBy = "rssChannel", cascade = CascadeType.ALL, orphanRemoval = true)
private List<RssFeed> feeds = new LinkedList<RssFeed>();
}
And RssCategory:
#Entity(name = "RssCategory")
#Table(name = "CATEGORY")
#JsonIgnoreProperties({"rssFeeds"})
public class RssCategory {
#Id
#GeneratedValue
#Column
private Integer id;
#Column(unique = true)
private String title;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "rssCategories")
public Set<RssFeed> rssFeeds = new LinkedHashSet<RssFeed>();
}
I use CrudRepository for manipulation with data. When save RssFeed without many to many it`s ok:
RssChannel channel = rssChannelService.get(url.toString());
rssFeed.setRssChannel(channel);
rssFeedService.save(rssFeed);
But when i add RssCategory:
rssCategory rssCategory = rssCategoryService.findOrCreate("test");
rssFeed.getRssCategories().add(rssCategory);
rssFeedService.save(rssFeed);
get exception: rg.hibernate.PersistentObjectException: detached entity passed to persist: RssCategory.
My RssFeedServiceImpl:
#Service
public class RssFeedServiceImpl implements RssFeedService {
#Autowired
private RssChannelDAO rssChannelDAO;
#Autowired
private RssFeedDAO rssFeedDAO;
#Override
public Page<RssFeed> findAll(Pageable pageable) {
return rssFeedDAO.findAll(pageable);
}
#Override
public Page<RssFeed> findAll(int rssChannelId, Pageable pageable) {
RssChannel rssChannel = rssChannelDAO.findOne(rssChannelId);
return rssFeedDAO.findByRssChannel(rssChannel, pageable);
}
#Override
public RssFeed get(String title) {
return rssFeedDAO.findByTitle(title);
}
#Override
public RssFeed save(RssFeed rssFeed) {
return rssFeedDAO.save(rssFeed);
}
}
And RssCategoryServiceImpl:
#Service
public class RssCategoryServiceImpl implements RssCategoryService {
#Autowired
RssCategoryDAO rssCategoryDAO;
#Override
public RssCategory findOrCreate(String title) {
RssCategory category = rssCategoryDAO.findByTitle(title);
if (category == null) {
category = new RssCategory();
category.setTitle(title);
category = rssCategoryDAO.save(category);
}
return category;
}
}
How save many to many?
You probably need to save your RssCategory first, in order to have an ID to store in feed_category table. This last save will be automatically made when you make the assignment:
rssFeed.getRssCategories().add(rssCategory);
but first you need to do:
rssFeedService.save(rssCategory);
Probably you'll need to put this operations within a transaction.
When i save the job entity i was expecting that the child under job should also reflect in the db. The problem is that the ref_id and revision does not contain any value from the db.
here is the result from mysql db (removed confidential data)
This is my Job entity class
#Entity
#Table(name = "job")
public class Job implements Serializable {
private static final long serialVersionUID = -2075866246194059832L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "ref_id")
private String refId;
#Column(name = "revision")
private int revision;
#Column(name = "appname")
private String appName;
#Column(name = "vendor")
private String vendor;
#Column(name = "version")
private String version;
#Column(name = "locale")
private String locale;
#Column(name = "platform")
private String platform;
#Column(name = "tier")
private String tier;
#Column(name = "category")
private String category;
#Column(name = "functional_tag")
private String functional;
#Column(name = "job_start_date")
private Date jobStartDate;
#Column(name = "author")
private String author;
#Enumerated(EnumType.STRING)
private Status status;
#Column(name = "release_version")
private String releaseVersion;
#OneToMany(mappedBy = "job", cascade = CascadeType.PERSIST)
private List<Task> tasks;
}
And here is the child
#Entity
#Table(name = "task")
public class Task implements Serializable {
private static final long serialVersionUID = -7395753611385528546L;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "module_name")
private String moduleName;
#Column(name = "start_time")
private Date startTime;
#Column(name = "end_time")
private Date endTime;
#Enumerated(EnumType.STRING)
private Status status;
#Column(name = "machine_ip")
private String machineIp;
#Column(name = "data_center")
private String dataCenter;
#Column(name = "description")
private String description;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumns({#JoinColumn(name = "ref_id", referencedColumnName = "ref_id"),
#JoinColumn(name = "revision", referencedColumnName = "revision")})
private Job job;
}
Here is the code that persist the entity
#Service
public class QReaderService {
#Autowired
private JobRepository jobRepository;
#Autowired
private TaskRepository taskRepository;
public boolean addJob(Job job) {
Job previousJob = jobRepository.findByJobRefId(job.getRefId());
if (previousJob == null) {
**jobRepository.save(job);**
return true;
} else {
switch (job.getStatus()) {
case FAILED:
case EXCEPTION:
int revision = 0;
revision += previousJob.getRevision();
previousJob.setStatus(Status.FAILED);
jobRepository.save(previousJob);
break;
}
}
return true;
}
}
This is how i build the job entity
Job job = new Job();
job.setRefId("f78d9as7f98dsa7f97a97f98sda9f7");
job.setAppName("appname");
job.setLocale("locale");
job.setPlatform("platform");
job.setCategory("category");
job.setReleaseVersion("1.1");
job.setStatus(Status.PROCESSING);
job.setAuthor("author");
job.setFunctional("functional");
job.setJobStartDate(new Date());
job.setVersion("1.1");
job.setTier("tier1");
job.setVendor("vendor");
Task task = new Task();
task.setDescription("description");
task.setDataCenter("dataCenter");
task.setStartTime(new Date());
task.setStatus(Status.PROCESSING);
task.setMachineIp("ip");
task.setModuleName("module");
job.setTasks(new ArrayList<Task>(Arrays.asList(task)));
jobRepository.save(job);
To persist child entities when you call save on parent entity, both sides of the relations should be set.
job.setTasks(job.setTasks(new ArrayList<Task>(Arrays.asList(task)));
//Missing line //Important for persistence of child
task.setJob(job);
Hope this helps.