How to get the result from select query using Spring boot - mysql

I have a native query in Spring-boot from which I want to get result using rest call, but I'm doing something wrong which is not giving me result. Please see my code below
When I call the repository from controller, it is giving me result, but when I try to call through service implementation, it is throwing me error.
Mysql result for select query I used:
mysql> select * from cricket_match;
[{ "id": 1,
"unique_id": 0,
"date": "2019-09-29T00:00:00.000Z",
"match_started": "Yes",
"team2": "St Lucia Zouks",
"team1": "Barbados Tridents"
},
{
"id": 2,
"date": "2019-08-08",
"team1": "India",
"unique_id": 12345,
"team2": "Australia",
"match_started": "No"
}]
mysql> SELECT unique_id, date, CASE WHEN match_started = 1 THEN 'Yes' ELSE 'No' END match_started, team1, team2, count(unique_id) AS weight FROM cricket_match GROUP BY unique_id, date, match_started, team1, team2 ORDER BY COUNT(unique_id)DESC;
[ {"unique_id": 0,
"date": "2019-09-29T00:00:00.000Z",
"match_started": "Yes",
"team2": "St Lucia Zouks",
"weight": 1,
"team1": "Barbados Tridents"
},
{
"date": "2019-08-08",
"weight": 1,
"team1": "India",
"unique_id": 12345,
"team2": "Australia",
"match_started": "No"
}]
MatchCount.java
package com.stackroute.matchrecommendationservice.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "match_recomendation")
public class MatchCount {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "unique_id")
private int unique_id;
#Column(name = "team1")
private String teamOne;
#Column(name = "team2")
private String teamTwo;
#Column(name = "date")
private String matchDate;
#Column(name = "match_started", columnDefinition = "TINYINT(1)")
private boolean matchStarted;
#Column(name = "user_id")
private String userId;
}
MatchCountRepository.java
import com.stackroute.matchrecommendationservice.domain.MatchCount;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.List;
import java.util.Map;
#RepositoryRestResource
public interface MatchCountRepository extends JpaRepository<MatchCount, Integer> {
List<MatchCount> findByUserId(String userId);
#Query(value = "SELECT unique_id, date, CASE WHEN match_started = 1 THEN 'Yes' ELSE 'No' END match_started, team1, team2, count(unique_id) AS weight FROM cricket_match GROUP BY unique_id, date, match_started, team1, team2 ORDER BY COUNT(unique_id)DESC", nativeQuery = true)
public List<Map<String,Object>> findRecommendations();
#Query(value = "SELECT unique_id, date, CASE WHEN match_started = 1 THEN 'Yes' ELSE 'No' END match_started, team1, team2, count(unique_id) AS weight FROM cricket_match GROUP BY unique_id, date, match_started, team1, team2 ORDER BY COUNT(unique_id)DESC", nativeQuery = true)
public List<MatchCount> findByRecommendations();
}
MatchRecommendationService.java
package com.stackroute.matchrecommendationservice.service;
import com.stackroute.matchrecommendationservice.domain.MatchCount;
import com.stackroute.matchrecommendationservice.exception.MatchAlreadyExistsException;
import com.stackroute.matchrecommendationservice.exception.MatchNotFoundException;
import java.util.List;
public interface MatchRecommendationService {
List<MatchCount> findByRecommendationServiceCall();
}
MatchRecommendationImpl.java
package com.stackroute.matchrecommendationservice.service;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.stackroute.matchrecommendationservice.domain.MatchCount;
import com.stackroute.matchrecommendationservice.exception.MatchAlreadyExistsException;
import com.stackroute.matchrecommendationservice.exception.MatchNotFoundException;
import com.stackroute.matchrecommendationservice.repository.MatchCountRepository;
import com.stackroute.rabbitmq.domain.MatchCountDTO;
#Service
public class MatchRecommendationImpl implements MatchRecommendationService{
private MatchCountRepository matchCountRepository;
#Autowired
public MatchRecommendationImpl(MatchCountRepository matchCountRepository) {
this.matchCountRepository = matchCountRepository;
}
#Override
public List<MatchCount> findByRecommendationServiceCall() {
var ResultMatches = (List<MatchCount>)matchCountRepository.findByRecommendations()
return ResultMatches;
}
}
MatchRecommendationController.java
package com.stackroute.matchrecommendationservice.controller;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.stackroute.matchrecommendationservice.repository.MatchCountRepository;
import com.stackroute.matchrecommendationservice.service.MatchRecommendationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.stackroute.matchrecommendationservice.domain.MatchCount;
import com.stackroute.matchrecommendationservice.exception.MatchAlreadyExistsException;
import com.stackroute.matchrecommendationservice.exception.MatchNotFoundException;
import com.stackroute.matchrecommendationservice.service.MatchRecommendationService;
#CrossOrigin
#RestController
#RequestMapping(path = "/api/v1/matchservice")
public class MatchRecommendationController {
private ResponseEntity responseEntity;
private MatchRecommendationService matchRecommendationService;
#Autowired
public MatchRecommendationController(final MatchRecommendationService matchService) {
this.matchRecommendationService = matchRecommendationService;
}
#Autowired
private MatchCountRepository matchCountRepository;
//Getting Result
#GetMapping("/{userId}/matchrecommendations")
public List<Map<String, Object>> getMatchrecommendations(){
return matchCountRepository.findRecommendations().stream().collect(Collectors.toList());
}
//Not Getting
#GetMapping("/matchrecommendationnew")
public String getMyMatchRecommendation(Model model) {
var results = (List<MatchCount>) matchRecommendationService.findByRecommendationsServiceCall();
model.addAttribute("results", results);
return "results";
}
}
From the controller when tested in POSTMAN, for
http://localhost:8080/api/v1/matchservice/matchrecommendations result is as below
[ {"unique_id": 0,
"date": "2019-09-29T00:00:00.000Z",
"match_started": "Yes",
"team2": "St Lucia Zouks",
"weight": 1,
"team1": "Barbados Tridents"
},
{
"date": "2019-08-08",
"weight": 1,
"team1": "India",
"unique_id": 12345,
"team2": "Australia",
"match_started": "No"
}]
For http://localhost:8080/api/v1/matchservice/matchrecommendationnew
I don't result, which should be same as above & below is the error
{
"timestamp": "2019-10-07T10:55:54.855+0000",
"status": 500,
"error": "Internal Server Error",
"message": "could not execute query; SQL [SELECT unique_id, date, CASE WHEN match_started = 1 THEN 'Yes' ELSE 'No' END match_started, team1, team2, count(unique_id) AS weight FROM cricket_match GROUP BY unique_id, date, match_started, team1, team2 ORDER BY COUNT(unique_id)DESC]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute query",
"path": "/api/v1/matchservice/matchrecommendationnew"
}
Error Log:
Hibernate: SELECT unique_id, date, CASE WHEN match_started = 1 THEN 'Yes' ELSE 'No' END match_started, team1, team2, count(unique_id) AS weight FROM cricket_match GROUP BY unique_id, date, match_started, team1, team2 ORDER BY COUNT(unique_id)DESC
2019-10-07 18:03:41.391 WARN 11720 --- [nio-8080-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: S0022
2019-10-07 18:03:41.395 ERROR 11720 --- [nio-8080-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : Column 'id' not found.
2019-10-07 18:03:41.516 ERROR 11720 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute query; SQL [SELECT unique_id, date, CASE WHEN match_started = 1 THEN 'Yes' ELSE 'No' END match_started, team1, team2, count(unique_id) AS weight FROM cricket_match GROUP BY unique_id, date, match_started, team1, team2 ORDER BY COUNT(unique_id)DESC]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute query] with root cause
java.sql.SQLException: Column 'id' not found.
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129) ~[mysql-connector-java-8.0.17.jar:8.0.17]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) ~[mysql-connector-java-8.0.17.jar:8.0.17]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89) ~[mysql-connector-java-8.0.17.jar:8.0.17]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63) ~[mysql-connector-java-8.0.17.jar:8.0.17]
at com.mysql.cj.jdbc.result.ResultSetImpl.findColumn(ResultSetImpl.java:548) ~[mysql-connector-java-8.0.17.jar:8.0.17]
at com.mysql.cj.jdbc.result.ResultSetImpl.getInt(ResultSetImpl.java:807) ~[mysql-connector-java-8.0.17.jar:8.0.17]
at com.zaxxer.hikari.pool.HikariProxyResultSet.getInt(HikariProxyResultSet.java) ~[HikariCP-3.2.0.jar:na] ...
Can you please help me how to write the correct controller mehtod to retrive the data and the Junit test case, for it.***

Thanks All, I was able to get the result when I changed the return type of
findByRecommendationServiceCall() to List<Map<String,Object>> from List<MatchCount>
The resultant changes are as below
MatchCountRepository.java
#Query(value = "SELECT unique_id, date, CASE WHEN match_started = 1 THEN 'Yes' ELSE 'No' END match_started, team1, team2, count(unique_id) AS weight FROM cricket_match GROUP BY unique_id, date, match_started, team1, team2 ORDER BY COUNT(unique_id)DESC", nativeQuery = true)
public List<Map<String,Object>> findByRecommendations();
MatchRecommendationService.java
List<Map<String,Object>> findByRecommendationServiceCall();
MatchRecommendationImpl.java
```
#Override
public List<Map<String,Object>> findByRecommendationServiceCall() {
var ResultMatches = (List<Map<String,Object>>)matchCountRepository.findByRecommendations()
return ResultMatches;
}
```
MatchRecommendationController.java
//Not Getting
#GetMapping("/matchrecommendationnew")
public String getMyMatchRecommendation(Model model) {
var results = (List<Map<String,Object>> matchRecommendationService.findByRecommendationsServiceCall();
model.addAttribute("results", results);
return results;
}

Related

Django - Raw query to ORM

models.py
class Employees(models.Model):
emp_no = models.IntegerField(primary_key=True)
birth_date = models.DateField()
first_name = models.CharField(max_length=14)
last_name = models.CharField(max_length=16)
gender = models.CharField(max_length=1)
hire_date = models.DateField()
class Meta:
managed = False
db_table = 'employees'
class Salaries(models.Model):
emp_no = models.ForeignKey(Employees, models.DO_NOTHING, db_column='emp_no',related_name='salaries', primary_key=True)
salary = models.IntegerField()
from_date = models.DateField()
to_date = models.DateField()
class Meta:
managed = False
db_table = 'salaries'
unique_together = (('emp_no', 'from_date'),)
Mysql raw query:
SELECT `employees`.`emp_no`, `employees`.`birth_date`, `employees`.`first_name`, `employees`.`last_name`, `employees`.`gender`, `employees`.`hire_date`,
(
SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'salary', `salaries`.`salary`,
'from_date', `salaries`.`from_date`,
'to_date', `salaries`.`to_date`
)
) FROM `salaries` WHERE (`employees`.`emp_no` = `salaries`.`emp_no`)
) as salaries
FROM `employees`
INNER JOIN `salaries` root_salaries ON `root_salaries`.`salary` > 60000
WHERE `employees`.`emp_no` = `root_salaries`.`emp_no` LIMIT 100 OFFSET 100
Output for raw query:
[
{
"emp_no": 10017,
"birth_date": "1958-07-06",
"first_name": "Cristinel",
"last_name": "Bouloucos",
"gender": "F",
"hire_date": "1993-08-03",
"salaries": [
{
"salary": 71380,
"to_date": "1994-08-03",
"from_date": "1993-08-03"
},
{
"salary": 75538,
"to_date": "1995-08-03",
"from_date": "1994-08-03"
}
]
},
{
"emp_no": 10018,
"birth_date": "1954-06-19",
"first_name": "Kazuhide",
"last_name": "Peha",
"gender": "F",
"hire_date": "1987-04-03",
"salaries": [
{
"salary": 55881,
"to_date": "1988-04-02",
"from_date": "1987-04-03"
},
{
"salary": 59206,
"to_date": "1989-04-02",
"from_date": "1988-04-02"
},
{
"salary": 61361,
"to_date": "1990-04-02",
"from_date": "1989-04-02"
}
]
}
]
My question is how to generate the above raw query using Django ORM.
Thanks.
Views.py
query_set = Employees.objects.filter(salaries__salary__gt=60000).annotate(
salaries_1=Subquery(
Salaries.objects.filter(emp_no=OuterRef('emp_no'), salary__gt=60000).values(
salaries=JSONArrayAgg(JSONObject(
salary=F('salary'),
from_date=F('from_date'),
to_date=F('to_date')
))))
).distinct()[100:200]
employee_ser = EmployeesWithSalaryGroupSerializer(query_set, many=True)
data = employee_ser.data
Serializers.py
class EmployeesWithSalaryGroupSerializer(serializers.Serializer):
emp_no = serializers.IntegerField()
birth_date = serializers.DateField()
first_name = serializers.CharField()
last_name = serializers.CharField()
gender = serializers.CharField()
hire_date = serializers.DateField()
salaries_1 = serializers.JSONField()
def to_representation(self, instance):
ret = super(EmployeesWithSalaryGroupSerializer, self).to_representation(instance=instance)
ret['salaries'] = json.loads(instance.salaries_1)
ret.pop('salaries_1')
return ret

Why is my data getting associated with wrong column in mysql db?

I have two tables connected with a many to many relationship using a composite key:
Table1
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "user_name")
private String userName;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
private String password;
private String authorization;
#OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true
)
#JsonManagedReference
private List<UserProduct> userProducts = new ArrayList<>();
#OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Orders> orders = new ArrayList<>();
Table2
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private int price;
private double mass;
private double alcohol;
private String picture;
private int amount;
#OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<UserProduct> userProducts = new ArrayList<>();
#OneToMany(
mappedBy = "orders",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<OrderProduct> orderProducts = new ArrayList<>();
Table with composite key
#Entity
#Table(name = "user_product")
public class UserProduct {
#EmbeddedId
private UserProductId id;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("userId")
#JsonBackReference
private User user;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("productId")
private Product product;
#Column(name = "amount_of_new_products")
private int amountOfNewProducts;
When I make a REST call to UserProduct table so i can update the product value using this payload:
{
"user": 4,
"product": 2,
"amountOfNewProducts": 32
}
it writes the information depending on what is the user id and not the product id. For this payload it would write in like this:
{
"id": 3,
"name": "Grimbergen Blanche",
"price": 132,
"mass": 0.33,
"alcohol": 6.0,
"picture": "https://i.imgur.com/qIq1OrC.png",
"amount": 502,
"userProducts": [],
"orderProducts": []
},
{
"id": 4,
"name": "Grimbergen Blonde",
"price": 132,
"mass": 0.33,
"alcohol": 6.7,
"picture": "https://i.imgur.com/OnioHd5.png",
"amount": 435,
"userProducts": [
{
"id": {
"productId": 2,
"userId": 4
},
"product": {
"id": 2,
"name": "Lav Premium",
"price": 73,
"mass": 0.33,
"alcohol": 4.9,
"picture": "https://i.imgur.com/T3gCAOE.png",
"amount": 1862,
"userProducts": [],
"orderProducts": []
},
"amountOfNewProducts": 32
}
],
"orderProducts": []
},
So basically even though i passed in 2 as product id the information will be written in product with id 4 just because the users id is 4. Any kind of a clue where I might me messing up would be appreciated.
You need to fix mappedBy = "user" in Product entity. It must be "product", like this:
#OneToMany(
mappedBy = "product",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<UserProduct> userProducts = new ArrayList<>();
Also check that you have correct #JoinColumn in UserProductId (ufortunately, you didn't put code for it to the question).

How to Left Join Model (or) Table in DRF

I have two models Employee and AccessDr.
Employee Model=>
class Employee(models.Model):
empid = models.CharField(max_length=20, unique=True)
empname = models.CharField(max_length=50)
phone = models.CharField(max_length=20, blank=True)
token = models.ForeignKey(
Company, to_field='token', on_delete=models.CASCADE)
def __str__(self):
return "%s" % (self.empid)
class Meta:
managed = True
db_table = 'employee'
AccessDr Model=>
class AccessDr(models.Model):
empid = models.ForeignKey(
Employee, to_field='empid', on_delete=models.CASCADE)
_date = models.DateField()
_time = models.IntegerField()
device = models.CharField(max_length=5)
takey = models.CharField(max_length=3, default='00')
token = models.ForeignKey(
Company, to_field='token', on_delete=models.CASCADE)
def __str__(self):
return "%s %s" % (self.empid, self._date)
class Meta:
ordering = ['_date']
managed = True
db_table = 'tstrdoor'
I would like to return object when the request to AccessDr like SQL left join, Example json=>
{
empid:'',
empname:'', <=this one from employee model
phone:'', <=this one from employee model
_date:'',
_time:'',
.
.
}
How can I achieve that one?
have a look at this LEFT JOIN Django ORM
read this as well https://docs.djangoproject.com/en/2.2/topics/db/queries/#spanning-multi-valued-relationships
you can print query to look at how it translates to SQL by
Employes=AccessDr.objects.values('employee__empname','employee__phone')
print(Employes.query)
Are you using serializers in the views? in this case, you could create a serializer field
which will put agreement data as an array like this
class CustomerSerializer(serializers.ModelSerializer):
agreements = AgreementSerializer(many=True, read_only=True)
class Meta:
model = Customer
fields = [
'id',
'username',
'mail',
'fName',
'lName',
'fNameEng',
'lNameEng',
'personalId',
'phone',
'crmId', # "ID": "20995",
'agreements',
]
depth = 1
Are you using serializers in the views? in this case, you could create serializer field
which will put agreement data as an array like this
{
"id": 985,
"username": null,
"mail": "undefined",
"fName": "Merab",
"lName": "Dasv",
"fNameEng": "Merab",
"lNameEng": "Dasv",
"personalId": "01022342346003629",
"phone": "5912324234282331",
"crmId": 1439,
"agreements": [
{
"id": 884,
"signDate": "2015-04-16",
"accountDate": "2015-05-01",
"amount": 0,
"comBalance": -1445.0,
"status": 1,
"details": [
{
"square": 32.38,
"amount": 35.0,
"object": {
"id": 578,
"object": 2,
"block": 1,
"floor": 19,
"flat": "7",
"cadastre": "05.24.04.055.01.563",
"square": 32.38,
"pCounter": 25915123146,
"wCounter": 104412312435,
"accountDate": "2015-04-01T00:00:00",
"comBalance": -1445.0,
"comDeptAmount": 1895.0,
"rentDate": null,
"active": 1,
"finaAmount": 0,
"crmId": 0
}
},
]
},
]
}

Spring Data JPA joining two or more entites

I have three entities,
#Entity
public class Deck {
#Id
private int id;
private int number;
private String name;
#OneToMany(mappedBy = "deck")
private Set<Lab> labs;
//getter and setter methods
}
#Entity
public class Lab {
#Id
private int id;
private String name;
#ManyToOne
private Deck deck;
#OneToMany(mappedBy = "lab")
private Set<LabBooking> labBooking;
//getter and setter methods
}
#Entity
public class LabBooking {
#Id
private int id;
private Date startTime;
private Date endTime;
#ManyToOne
private Lab lab;
//getter and setter methods
}
Following is the LabRepository,
public interface LabRepository extends CrudRepository<Lab, Integer>{
#Query("SELECT l FROM Lab l JOIN l.labBooking lb WHERE l.deck.id = :deckId AND lb.startTime > '2016-02-24 15:00:00'")
List<Lab> findLabs(#Param("deckId") int deckId);
}
I am trying to retrieve the list of Labs in a deck which are occupied from a particular time.
When I execute the equivalent query (SELECT * FROM lab l JOIN lab_book lb ON l.id = lb.lab_id WHERE l.deck_id = 9999 AND lb.start_time > '2016-02-24 15:00:00') in MySQL, I am getting the following result
id name deck_id id end_time start_time lab_id
9001 Lab One 9999 5 2016-02-24 17:00:00 2016-02-24 16:00:00 9001
In the spring application I am getting the following result,
[{
"lab_id": 9001,
"lab_name": "Lab One",
"lab_booking": [{
"id": 4,
"start_time": "2016-02-24 15:00:00",
"end_time": "2016-02-24 16:00:00"
}, {
"id": 5,
"start_time": "2016-02-24 16:00:00",
"end_time": "2016-02-24 17:00:00"
}, {
"id": 3,
"start_time": "2016-02-24 14:00:00",
"end_time": "2016-02-23 14:30:00"
}]
}]
The Lab object was supposed to contain only the booking id 5, instead it shows all the ids.
If the sql query return 5 records, then the repository returns 5 Lab objects which are duplicate. What may be the issue?
Seems that your missing distinct.
SELECT distinct l FROM Lab l JOIN l.labBooking lb WHERE l.deck.id = :deckId AND lb.startTime > '2016-02-24 15:00:00'"

Adding information from one JsonBuilder object to another

As the title suggests, I'm trying to add information held in one JsonBuilder object to a second JsonBuilder object.
Currently I have this:
public String buildOneUser(DyveUserDTO user)
{
def userBuilder = new JsonBuilder()
userBuilder user.collect { usr ->
[
'Name': usr.userName,
'Allowance': usr.allowance,
'Total Holidays in Calendar': usr.totalHolidaysInCal,
'Holidays Booked': usr.numHolidaysBooked,
'Holidays Taken': usr.numHolidaysTaken,
'Holidays Remaining': usr.totalHolidaysLeft
]
}
def userHolidayBuilder = new JsonBuilder()
userHolidayBuilder user.holidayEvents.collect { usr ->
[
'Start Date': usr.startDate,
'End Date': usr.endDate,
'Days': usr.days
]
}
def userAndHolidays = userBuilder + userHolidayBuilder
return userAndHolidays.toPrettyString()
}
user.holidayEvents is a list of objects representing holidays and it could be empty or have any number of objects in it. This made me hesitant of doing something like:
def userBuilder = new JsonBuilder()
userBuilder user.collect { usr ->
[
'Name': usr.userName,
'Allowance': usr.allowance,
'Total Holidays in Calendar': usr.totalHolidaysInCal,
'Holidays Booked': usr.numHolidaysBooked,
'Holidays Taken': usr.numHolidaysTaken,
'Holidays Remaining': usr.totalHolidaysLeft
'Holiday': usr.holidayEvents[0].startDate
'Holiday': usr.holidayEvents[0].endDate
'Holiday': usr.holidayEvents[0].days
]
}
As I would only get the amount of holidays I write code for. It would also throw an exception if a user had no holidays and I told it look at usr.holidayEvents[1] as it's outside of the list range.
I've also tried nesting a .collect like this
def userBuilder = new JsonBuilder()
userBuilder {
'Name' user.userName,
'Allowance' user.allowance,
'Total Holidays in Calendar' user.totalHolidaysInCal,
'Holidays Booked' user.numHolidaysBooked,
'Holidays Taken' user.numHolidaysTaken,
'Holidays Remaining' user.totalHolidaysLeft,
'Holidays' user.holidayEvents.collect{ evt ->
[
'Start Date': evt.startDate,
'End Date': evt.endDate,
'Days': evt.days
]
}
}
But this returned all the keys except the Holidays key.
Any help would be greatly appreciated!
EDIT - My code now looks like this:
public String buildOneUser(DyveUserDTO user)
{
def userBuilder = new JsonBuilder()
userBuilder user.collect { usr ->
[
'Name': usr.userName,
'Allowance': usr.allowance,
'Total Holidays in Calendar': usr.totalHolidaysInCal,
'Holidays Booked': usr.numHolidaysBooked,
'Holidays Taken': usr.numHolidaysTaken,
'Holidays Remaining': usr.totalHolidaysLeft,
'Holidays': usr.holidayEvents.collect{ evt ->
[
'Start Date': evt.startDate,
'End Date': evt.endDate,
'Days': evt.days
]
}
]
}
}
EDIT 2 - Sample Code
Method to call:
public String buildOneUser(DyveUserDTO user)
{
def userBuilder = new JsonBuilder()
userBuilder {
Name:
user.userName
Allowance:
user.allowance
TotalHolidaysInCalendar:
user.totalHolidaysInCal
HolidaysBooked:
user.numHolidaysBooked
HolidaysTaken:
user.numHolidaysTaken
HolidaysRemaining:
user.totalHolidaysLeft
Holidays:
user.holidayEvents.collect { evt ->
[
'Start Date': evt.startDate,
'End Date' : evt.endDate,
'Days' : evt.days
]
}
}
return userBuilder.toPrettyString()
}
User to pass in:
class DyveUserDTO
{
String firstName = "Foo"
String userName = "FooBar"
Integer userID = 42
BigDecimal numHolidaysBooked = 3
BigDecimal numHolidaysTaken = 0
BigDecimal totalHolidaysInCal = 3
BigDecimal totalHolidaysLeft = 12
BigDecimal allowance = 12
List<HolidayObject> holidayEvents = []
}
Holiday objects to go in holidayEvents:
class HolidayObject
{
public Integer userID = 42
public String title = "Foo Holiday"
public String event = "Holiday"
public String amPm = "Full Day"
public String name = "Foo"
public LocalDateTime startDate = LocalDateTime.parse(2015-02-20T00:00:00)
public LocalDateTime endDate = LocalDateTime.parse(2015-02-20T00:00:00)
public BigDecimal days = 1
}
class HolidayObject
{
public Integer userID = 42
public String title = "Foo Holiday Pm"
public String event = "Holiday"
public String amPm = "Pm"
public String name = "Foo"
public LocalDateTime startDate = LocalDateTime.parse(2015-02-23T00:00:00)
public LocalDateTime endDate = LocalDateTime.parse(2015-02-24T00:00:00)
public BigDecimal days = 2
}
each just returns the list it's called upon, collect should be used for events. See the working code below:
import groovy.json.JsonBuilder
class UserEvent {
def start
def end
def days
}
class User {
def name
def events
}
def u1 = new User(name: 'u1', events: [new UserEvent(start: 0, end: 1, days: 1), new UserEvent(start: 0, end: 2, days: 2)])
def u2 = new User(name: 'u2', events: [new UserEvent(start: 0, end: 3, days: 3)])
def users = [u1, u2]
def userBuilder = new JsonBuilder()
userBuilder users.collect { usr ->
[
'name': usr.name,
'events': usr.events.collect { e ->
[
start: e.start,
end: e.end,
days: e.days,
]
}
]
}
print userBuilder.toPrettyString()
EDIT
Below is a working example:
import groovy.json.JsonBuilder
user = new DyveUserDTO()
def userBuilder = new JsonBuilder()
userBuilder {
Name user.userName
Allowance user.allowance
TotalHolidaysInCalendar user.totalHolidaysInCal
HolidaysBooked user.numHolidaysBooked
HolidaysTaken user.numHolidaysTaken
HolidaysRemaining user.totalHolidaysLeft
Holidays user.holidayEvents.collect { evt ->
[
'Start Date': evt.startDate,
'End Date' : evt.endDate,
'Days' : evt.days
]
}
}
println userBuilder.toPrettyString()
class DyveUserDTO {
String firstName = "Foo"
String userName = "FooBar"
Integer userID = 42
BigDecimal numHolidaysBooked = 3
BigDecimal numHolidaysTaken = 0
BigDecimal totalHolidaysInCal = 3
BigDecimal totalHolidaysLeft = 12
BigDecimal allowance = 12
List<HolidayObject> holidayEvents = [new HolidayObject(), new HolidayObject()]
}
class HolidayObject {
public Integer userID = 42
public String title = "Foo Holiday"
public String event = "Holiday"
public String amPm = "Full Day"
public String name = "Foo"
public String startDate = '2015-02-20T00:00:00'
public String endDate = '2015-02-20T00:00:00'
public BigDecimal days = 1
}
No colons : needed. See the sample here. Also I have no Joda dependency so replaced with String.