Conversion dto to entity for a list - java

In a spring boot application with jpa.
I have a Entity with a one to many relation.
I create a dto with a list who represent this entity.
When i receive the dto from the client and convert to the entity, we do some validation to add new object, update existing object and remove object user have decided
protected void convertToBeans(CarDto dto, Car bean) {
List < CarComponentOccurrencesDto > dtoAircraftComponentOccurrences = dto.getCarComponentOccurrences();
dtoCarComponentOccurrences = (dtoCarComponentOccurrences == null) ?
new ArrayList < > () : dtoCarComponentOccurrences;
// when a param is removed in the middle of the list, the list replace the removed element by a null othewise, that keep the same size, this cause null pointer exceptions.
dtoCarComponentOccurrences.removeIf(Objects::isNull);
List < CarComponentOccurrences > beanCarComponentOccurrences = bean.getCarComponentOccurrences();
// remove items who dont exist anymore
List < CarComponentOccurrences > carComponentOccurrencesToRemove = new ArrayList < > ();
for (CarComponentOccurrences occurence: beanCarComponentOccurrences) {
if (dtoCarComponentOccurrences.stream().noneMatch(e - > Objects.equals(e.getId(), occurence.getId()))) {
carComponentOccurrencesToRemove.add(occurence);
}
}
for (CarComponentOccurrences toRemove: carComponentOccurrencesToRemove) {
bean.removeCarComponentOccurrences(toRemove);
}
// add items that do not exist
for (CarComponentOccurrencesDto carComponentOccurrenceDto: dtoCarComponentOccurrences) {
if (carComponentOccurrenceDto.getId() == null || beanCarComponentOccurrences.stream().noneMatch(e - > Objects.equals(e.getId(), carComponentOccurrenceDto.getId()))) {
CarComponentOccurrences carComponentOccurrence = new CarComponentOccurrences();
if (carComponentOccurrenceDto.getComponentNameId() != null) {
Optional < CarComponents > optCarComponents = carComponentsRepository
.findById(carComponentOccurrenceDto.getComponentNameId());
if (optCarComponents.isPresent()) {
carComponentOccurrence.setCarComponent(optCarComponents.get());
}
carComponentOccurrence.setCarService(bean);
carComponentOccurrence.setCode(carComponentOccurrenceDto.getCode());
bean.addCarComponentOccurrences(aircraftComponentOccurrence);
}
}
}
}
is there a way to manage create, update and delete item from a list when we attach to entity with mapstruct or we need to that way ?
i found that a lot of boilerplate code

Related

getting an object data inside an object in java

i have a x object that contains a object inside , and i would like to acess it from a method without extra write code.
Let's say this is my object :
{
"status": "Success",
"code": "200 OK",
"message": "OK",
"data": {
"renter": {
....some Hashmap information.......
}
}
}
lets say i want to access the information the object renter inside the object data brings .
For that
in my method Y i did this :
#Override
public Y methodY(String userName) throws Exception{
ObjectMapper mapper = new ObjectMapper();
Map<String,Object> clienteFeignOnMap= client.findByRenterName(userName);
//////////ACCESSING THE OBJECT DATA//////////////////
Map<String,Object> objectResponseData= (Map<String, Object>) clienteFeignOnMap.get("data");
//////////ACCESSING THE OBJECT RENTER INSIDE DATA FOR DESERIALIZING TO TyPE RENTER//////////////////
Renter renter = mapper.convertValue(objectResponseData.get("renter"), new TypeReference<Renter>(){ });
......more code.............
}
This way is successful and works, but still i think i could find a better option that allows me on one line resume that access from the inner object renter .
Thanks in advance for any help or suggestion. Happy ne year 2021
If you don't want to create a Java class to map the attributes as #Migwel suggested and want to use java.util.Map, then you may have to use Apache BeanUtils or something equivalent to get to deep elements.
BeanUtils.getNestedProperty( map, elementPath )
where elementPath is a dot separated path to the element. data.renter, in your case.
PropertyUtils.getNestedProperty( map, elementPath ) also does the same thing.
However, these will not let you access indexed properties, in case you have arrays within the objects. For that, as far as I know, you will have to write custom code akin to the method below.
public static <T> T getMapElement( Map<String, ? super Object> map, String path ) {
if( isEmpty( path ) ) return null;
String[] parts = path.split( "[\\[\\]\\.]" );
Object currElem = null;
try{
currElem = map;
for( int i = 0; i < parts.length; i++ ){
String part = parts[ i ];
boolean done = false;
/* Handle List. */
if( currElem instanceof List ) {
int index = integer( part, -1 );
if( index >= 0 ) {
currElem = ( (List) currElem ).get( index );
done = true;
}
}
if( done ) continue;
/* Handle Map. */
if( currElem instanceof Map ) currElem = ( (Map) currElem ).get( part );
if( currElem == null ) break;
};
}
catch( Exception e ){}
return (T) currElem;
}
Edit
There is also json-path from group com.jayway.jsonpath that also allows one to inspect a JSON directly into deep elements. Disclaimer: I haven't used and am not sure what it uses to deserialize the JSON. However, it may be worth a research.
Instead of using maps, you should create proper objects.
For example:
public class Response {
private String status;
private String code;
private String message;
private Data data;
// constructor, getters, setters
...
}
And so on with a class Data and a class Renter, etc.
Then, when using objectMapper, you can directly deserialize it into your Response object

How to delete a list of entities

I have a JPA query to delete selected entities which is stored in a list. I am currently deleting the entities in a loop via the in built JPA delete() method 1 by 1. Is there a way to just pass in the list instead of looping it?
Current implementation that works but looping to delete 1 by 1. I need the initial query to get list of entities for other reasons thus not looking to change that. Just a way to pass in the list of entiies to be deleted. Please advice. Thanks.
Note: This is with Java 8 and Spring 4.3 if it matters.
#GetMapping("/delete/{name}/{count}")
public String delete(#PathVariable String name, #PathVariable int count){
boolean isDelete = true;
while (isDelete){
//1st query
List<PersonEntity> results = personService.get(name, count);
if(results != null && !results.isEmpty()){
System.out.println("Deleting following: ");
//2nd query
results.forEach(p -> {
System.out.println(p.getName());
personService.delete(p);
});
} else {
isDelete = false;
}
}
return "Done!";
}
You can try something like this:
List<PersonEntity> results = personService.get(name, count);
if(results != null && !results.isEmpty()) {
List<Integer> personIds = results.stream()
.map(personIds)
.collect(Collectors.toList());
personService.deleteManyById(personIds);
In your service:
public void deleteManyById(List<Integer> ids) {
personRepository.deleteByIdIn(ids);
}
In your repo (assuming it's a spring JpaRepository):
void deleteByIdIn(List<Integer> ids);
Just be aware of the fact that dbs have a limit in the number of parameters you can pass in a IN condition

Refactor multiple If' statements in Java-8

I need to validate mandatory fields in my class
For example, 9 fields must not be null.
I need to check if they are all null but I am using multiple if statements for this now as below:
StringBuilder mandatoryExcessFields = new StringBuilder(MANDATORY_EXCESS_FIELDS.length);
if(Objects.isNull(excess.getAsOfDate())){
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[0]);
}
if(StringUtils.isEmpty(excess.getStatus())) {
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[1]);
}
if(Objects.isNull(excess.getLimit())) {
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[2]);
}
if(!Objects.isNull(excess.getLimit()) && Objects.isNull(excess.getLimit().getId())) {
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[3]);
}
if(!Objects.isNull(excess.getLimit()) && Objects.isNull(excess.getLimit().getAsOfDate())) {
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[4]);
}
if(Objects.isNull(excess.getExposure())) {
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[5]);
}
if(!Objects.isNull(excess.getExposure()) && Objects.isNull(excess.getExposure().getCoordinates())) {
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[6]);
}
if(!Objects.isNull(excess.getExposure()) && Objects.isNull(excess.getExposure().getValue())) {
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[7]);
}
if(StringUtils.isEmpty(excess.getLimitValue())) {
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[8]);
}
Do we have a better approach to reduce this boilerplate code or any design pattern or any new feature from Java-8 which I can leverage?
All the Object.isNull might be replaced with Optional object and its methods. Let's take example the line:
if (!Objects.isNull(excess.getLimit()) && Objects.isNull(excess.getLimit().getId())) {
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[3]);
}
Would be simplified to (and squeezed on 1 line remains readable):
Optional.ofNullable(excess.getLimit()) // check the Limit
.map(limit -> limit.getId()) // if not null, getId
.ifPresent(i -> builder.append(MANDATORY_EXCESS_FIELDS[3])); // Append if present
And for the String.isEmpty(s) check, you have to create Optional in this way:
Optional.ofNullable(excess.getStatus()).filter(s -> !StringUtils.isEmpty(s))
A short way would be to pass those Optional object into the map and use the index to iterate through them and perform an action. int count is a number of checkings:
Map<Integer, Optional<?>> map = new HashMap<>();
map.put(...);
map.put(1, Optional.ofNullable(excess.getStatus()).filter(s -> !StringUtils.isEmpty(s)));
map.put(...);
map.put(3, Optional.ofNullable(excess.getLimit()).map(limit -> limit.getId()));
map.put(...);
for (int index=0; index<count; index++) {
map.get(index).ifPresent(any -> mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[index]));
}
And the for-cycle might be simplified as well:
IntStream.range(0, count).forEach(index ->
map.get(index)
.ifPresent(any -> mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[index])));
Basically, there are two ways here:
As suggested by the comment, NonNull as offered by Project Lombok for example
Java bean validation
I would heavily recommend to look into bean validation:
Define your classes that carry information as beans. And then use the wide range of annotations to mark the corresponding fields. And then use some existing framework to do the validation for you. You can even define your own annotations there, that run your own code.
You can use javax.validator and hibernate.validator with #NotNull annotation on each field (or whichever field you want) on your excess POJO class. This combination provides an extensive pattern checking as well.
By this you don't have to do all the if checks explicitly. You can get ride of not only null checks but also pattern matching checks which can get scattered all over your code.
Basically the initialisation and assignments should not set any field to null.
If this is unopportune (a field being really logically optional), the field should probably be an Optional<...>, assigned with an Optional.ofNullable(...). This ensures that at usage the field is safely processed, but causes editing work of course.
Seeing the code now, here it seems that there is no easy refactoring.
The code could be refactored; somewhere a mapping of features is missing.
Predicate<Excess>[] parts = {
exc -> Objects.isNull(exc.getAsOfDate()),
exc -> StringUtils.isEmpty(exc.getStatus()),
...
};
for (int i = 0; i < parts.length; ++i) {
if (parts[i].test(excess)) {
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[i]);
}
}
Or such.
As easy refactoring you could introduce two helper methods :
private String createErrorMsgIfObjectNull(Object o, String errorMessage) {
return Objects.isNull(o) ? errorMessage : "";
}
private String createErrorMsgIfStringEmpty(String s, String errorMessage) {
return StringUtils.isEmpty(s) ? errorMessage : "";
}
And use them in this way :
StringBuilder mandatoryExcessFields = new StringBuilder(MANDATORY_EXCESS_FIELDS.length);
mandatoryExcessFields.append(createErrorMsgIfObjectNull(excess.getAsOfDate(), MANDATORY_EXCESS_FIELDS[0]))
.append(createErrorMsgIfStringEmpty(excess.getStatus(), MANDATORY_EXCESS_FIELDS[1]))
.append(createErrorMsgIfObjectNull(excess.getLimit(), MANDATORY_EXCESS_FIELDS[2]))
// ...
By checking the type of the object to test you could still go further. You would have a single helper method that will apply the processing according to the argument type :
private String createErrorMsgIfNullOrEmptyString(Object o, String errorMessage) {
if (o instanceof String) {
return StringUtils.isEmpty((String)o) ? errorMessage : "";
}
return Objects.isNull(o) ? errorMessage : "";
}
A Java 8 stream way would inline the helper in a filter and map() operations and would collect the String result :
List<SimpleImmutableEntry<Object, String>> objectAndErrorMessageList = new ArrayList<>();
int i = 0;
objectAndErrorMessageList.add(new SimpleImmutableEntry<>(excess.getAsOfDate(), MANDATORY_EXCESS_FIELDS[i++]));
objectAndErrorMessageList.add(new SimpleImmutableEntry<>(excess.getStatus(), MANDATORY_EXCESS_FIELDS[i++]));
// and so for
String globalErrorMsg =
objectAndErrorMessageList.stream()
.filter(e -> {
Object objectToValid = e.getKey();
if (objectToValid == null) {
return true;
}
if (objectToValid instanceof String && StringUtils.isEmpty(objectToValid)) {
return true;
}
return false;
})
.map(SimpleImmutableEntry::getValue)
.collect(Collectors.joining(""));
Other solution would be like this: same as #Nikolas answer.
Map<Integer, Predicate<Excess>> map = new HashMap<>();
Predicate<Excess> checkStatus = excess -> excess.getStatus().isEmpty();
Predicate<Excess> checkLimit = excess -> Objects.isNull(excess.getLimit());
Predicate<Excess> checkLimitId = excess -> Objects.isNull(excess.getLimit().getId());
Predicate<Excess> checkLimitAndId = checkLimit.and(checkLimitId);
// other predicates
map.put(1,checkStatus);
map.put(2,checkLimit);
map.put(3,checkLimitAndId);
// put other predicates ...
for (Map.Entry<Integer, Predicate<Excess>> m : map.entrySet()) {
if (m.getValue().test(excess)) {
mandatoryExcessFields.append(MANDATORY_EXCESS_FIELDS[m.getKey()]);
}
}
A little bit complicated, but I have a good solution because it's generic and can be used with any objects:
Excess excess = new Excess(new Limit());
Checker<Excess, Excess> checker = new Checker<>(
identity(),
List.of(
new CheckerValue<>("excess date is null", Excess::getAsOfDate),
new CheckerValue<>("limit is null", Excess::getLimit)
),
List.of(new Checker<>(Excess::getLimit, List.of(new CheckerValue<>("limit id is null", Limit::getId))))
);
System.out.println(checker.validate(excess));
This code will print:
excess date is null
limit id is null
The first class Checker contains:
sourceFunction - for getting the object
values - for checking each field from object obtained from sourceFunction
children - a list of Checker
class Checker<S, T> {
Function<S, T> sourceFunction;
List<CheckerValue<T>> values;
List<Checker<T, ?>> children = emptyList();
/*All args constructor; 2 args constructor*/
public String validate(S object) {
T value = sourceFunction.apply(object);
if(value != null) {
String valueString = values.stream().map(v -> v.validate(value)).filter(Optional::isPresent).map(Optional::get).collect(joining("\n"));
valueString += "\n\t";
valueString += children.stream().map(c -> c.validate(value)).collect(Collectors.joining("\n"));
return valueString;
}
return "";
}
}
and CheckerValue class:
class CheckerValue<T> {
String validationString;
Function<T, Object> fun;
/*all args constructor*/
public Optional<String> validate(T object) {
return fun.apply(object) != null ? Optional.empty() : Optional.of(validationString);
}
}

How can I avoid stackoverflow exception

I have a list of hierarchical objects and I have to remove a hierarchy if a hierarchy has a value as zero.
I have to remove all the managers(employees)
if and only if emp salary is 0 and there are no employees under him.
OR all the employees under him having zero salary.
But not if manager salary is having zero and employees under him does not have zero salary.
Eg.
emp(10)
|---- empA(9)
|---- empAa(8)
|---- empAb(7)
|---- empAc(0)
|---- empB(7)
|---- empBa(0)
|---- empBaa(0)
|---- empBaaa(0)
|---- empBb(0)
|---- empBba(4)
above structure has to be modified as below.
emp(10)
|---- empA(9)
|---- empAa(8)
|---- empAb(7)
|---- empB(7)
|---- empBb(0)
|---- empBba(4)
I am getting stackoverflow exception when the input list is big. how should I enhance this logic to avoid SOFE.
removeHierarchy(List<Employee> managers){
int count = 0;
if(null != managers && !managers.isEmpty()){
for(Employee manager: managers){
List<Employee> toBeRemoved = new ArrayList<>();
List<Employee> employees = manager.getEmployees();
if(0 == manager.getSalary()){
if(null == employees || employees.isEmpty()){
toBeRemoved.add(manager);
} else {
++count;
removeHierarchy(employees);
}
} else {
removeHierarchy(employees);
}
managers.removeAll(toBeRemoved);
}
}
for(int i=0; i < count; i++){
removeHierarchy(managers);
}
}
I think your problem is that you don't actually remove any employees from the lists. If the list has such configuration - you will go in infinite cycles on last lines.
emp(0)
|---- empA(0)
It seems the last lines should be something like managers.removeAll(toBeRemoved)
Here is working function:
void removeHierarchy( List<Employee> managers )
{
List<Employee> toBeRemoved = new ArrayList<>();
for ( Employee manager : managers )
{
removeHierarchy( manager.getEmployees() );
if (0 == manager.getSalary() && manager.getEmployees().isEmpty()) {
toBeRemoved.add( manager );
}
}
managers.removeAll( toBeRemoved );
}
See full test code
To decide whether you have to keep or remove an Employee, you must first process her employees' list:
void removeHierarchy(List<Employee> managers){
if(null != managers && !managers.isEmpty()){
List<Employee> toBeRemoved = new ArrayList<>();
for(Employee manager: managers) {
List<Employee> employees = manager.getEmployees();
removeHierarchy(employees);
if (0 == manager.getSalary()
&& (null == employees || employees.isEmpty())) {
toBeRemoved.add(manager);
}
}
managers.removeAll(toBeRemoved);
}
}
I think this program has multiple problems.
You cannot iterate over a list and try to manipulate it at same time
There's is no logic to remove the identified managers/employees
As suggested by John, I'm adding method that can perform the required task. It is no different that the solution provided in other answer except that I have used Java 8 syntactic sugar.
public static boolean removeEmployee(Employee employee)
{
employee.setEmployees(employee.getEmployees().stream().filter(Employee::removeEmployee).collect(Collectors.toList()));
return !(employee.getSalary()==0 && employee.getEmployees().size()==0);
}
Note: Make sure your array list (list of employees) is not null i.e., empty array list when you create an employee object.

filtering out the list data if the attributes are null itself

I have the below class named BrokerInvoice which contain the following member variables
public class BrokerInvoice
{
private List<BrokerInvoiceLineItem> lineItems;
//and its corresponding setters and getters
}
I have the below java class named BrokerInvoiceLineItem as shown below which has a relationship among the top class named brokerInvoice as the below class is added in the to class as a list
public class BrokerInvoiceLineItem {
private String brokerRefId;
private double notional;
private Date dealDate;
//corresponding setters and getters
}
now in some piece of code i am getting the object of parent class that is of broker invoice itself
BrokerInvoice brokerInvoice1 = abc.findrty( brokerIdLong , serType );
now the above brokerInvoice1 object contain the entries of lineItems that is of type BrokerInvoiceLineItem also , so i want to edit the list named lineitems such that the list i am getting inside the brokerInvoice1 object as the condition is that there should be a sort of pre check that if lineitems list attributes named brokerRefId,notional,dealDate,dealDate are null then that entry should not be there in the line items list itself
so please advise how can i filter out my lineitems list residing inside brokerInvoice1 object such that there should not be no null attribute entry inside the lineitemslist if these attribute are empty
I am using Java 5 please advise how to achieve this can I achieve the same by java5
If you are on Java 8 you can use removeIf from Collection:
listItems.removeIf(i -> i.getBrokerRefId() == null || i.getDealDate() == null);
This assuming you want to mutate the list.
If you prefer to not change the listItems, and only get a new list without the wrong items, you can use stream filtering:
List<BrokerInvoiceLineItem> newList = listItems.stream()
.filter(i -> i.getBrokerRefId() != null)
.filter(i -> i.getDealDate() != null)
.collect(Collector.toList());
Notice, that the stream version retains items that match the predicate and the removeIf one does the opposite, so the predicates are inverted.
Java 5 :
private List<BrokerInvoiceLineItem> newLineItems = new ArrayList<BrokerInvoiceLineItem>();
if (brokerInvoice1 != null && brokerInvoice1.lineItems != null){
for(BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoice1.lineItems){
if(brokerInvoiceLineItem.getBrokerRefId() != null && brokerInvoiceLineItem.getDealDate() == null){
newLineItems.add(brokerInvoiceLineItem)
}
}
}

Categories