user class with fields id, name and types
public class User {
private String id;
private String name;
private List<Types> types;
}
Types class with fields id, name , linkedTo
{
private String id;
private String name;
private String linkedTo;
}
Implemented a method to get types from user and return it as list
private List<Types> getType(List<User> Users) {
return Users
.stream()
.map(User::gettypes)
.flatMap(List::stream)
.collect(Collectors.toList());
}}
Now, have to map to response body. For that I have response class:
public class UserResponse {
private String id;
private String type;
private String name;
private String linkedTo;
}
Have to map the fields from Types to user response to return it as list
private List<UserResponse> getUserResponse(UserRequest request) {
List<User> Users = userServiceClient.getById();
List<UserResponse> userResponses = new ArrayList<>();
List<Types> TypesList = getType(Users);
if (!typesList.isEmpty()) {
return typesList.stream()
.map(type -> userResponses.add(new UserResponse( type.getGuid(),type.getName(),type.getName(),type.getLinkedTo())))
.collect(Collectors.toList());
}
return collections.emptylist();
}
Here is the problem, I'm not able to return it as list instead getting a boolean..
Is there any efficient way to do this? The code reviewer doesn't want me to use for each and return the list
A better appraoch would be
private List<UserResponse> getUserResponse(UserRequest request) {
List<User> Users = userServiceClient.getById();
List<Types> TypesList = getType(Users);
return typesList.stream()
.map(type -> new UserResponse(type.getId(), type.getName(), type.getName(), type.getLinkedTo()))
.collect(Collectors.toList());
}
Reason:
If typesList is empty, this would return empty List, as Collections.emptyList in your code.
It maps to the UserResponse objects and collects them to return the List<UserResponse> while using the Stream for it without the explicit instantiation and .add call.
Related
I am trying to find string with max length of a given attribute of java. I will pass the attribute name as string into the method which will return me the string value of max length.
class Employee {
private String name;
private String designation;
private List<Address> address;
private ContactInfo contactInfo;
....
getter setter
}
class Address {
private String city;
private String state;
private String country;
......
getter setter
}
class ContactInfo {
private String mobileNumber;
private String landlineNumber;
....
getter setter
}
I have some data just like below:
ContactInfo contactInfo = new ContactInfo("84883838", "12882882");
Address address1 = new Address("city111", "state111", "country111");
Address address2 = new Address("city111111", "state11112", "country1112");
Employee employee1 = new Employee("xyz", "uyyy", List.of(address1, address2), contactInfo);
private String findStringWithMaxLength(String attribute) {
return employeeList.stream()
....
}
In above case, if I provide attribute value as "city" then it should return me the value "city111111" because of maximum string length.
If we have child objects and list of objects, how do I traverse with the given attribute.
You can create a method that take a list of employees and a function to get the specific attribute like this:
private String findStringWithMaxLength(List<Employee> employees, Function<Employee, String> function) {
return employees.stream()
.map(function)
.max(Comparator.comparing(String::length))
.orElseThrow(() -> new IllegalArgumentException("Empty list"));
}
and to call the method you can use:
findStringWithMaxLength(employees, Employee::getName)
findStringWithMaxLength(employees, Employee::getDesignation)
findStringWithMaxLength(employees, Employee::getAddress)
Note that the method will throw an exception if the list is empty, if you wont throw an exception, then you can replace it with orElse(withDefaultValue)
You can do it using reflection but here is a better "typesafe" way.
Let the class:
#Getter
#Setter
#AllArgsConstructor
static class Employee {
private String name;
private String designation;
private String address;
}
with getters and let the list
static List<Employee> employeeList = asList(
new Employee("xyz1", "abc1234", "address 123"),
new Employee("xyz123", "abc123", "address 1234"),
new Employee("xyz1234", "abc12", "address 12")
);
then, you can define a generic function able to traverse any String field
static Optional<String> findStringWithMaxLength(Function<Employee, String> getter) {
return employeeList.stream().map(getter).max(Comparator.comparingInt(String::length));
}
now, you can apply every getter to that function
for(Function<Employee, String> getter: Arrays.<Function<Employee, String>>asList(
Employee::getName,
Employee::getDesignation,
Employee::getAddress))
System.out.println(findStringWithMaxLength(getter));
with output
Optional[xyz1234]
Optional[abc1234]
Optional[address 1234]
(the optional is required since the list could be empty).
The given answers work fine. I'd like to use an enum in this case. If a method changes in the Employee class, you only have to change the enum, not every call using it:
enum EmployeeField {
NAME(Employee::getName),
DESIGNATION(Employee::getDesignation),
ADDRESS(Employee::getAddress);
private final Function<Employee, String> getter;
EmployeeField(Function<Employee, String> getter) {
this.getter = getter;
}
public Function<Employee, String> getGetter() {
return getter;
}
}
private static final List<Employee> employeeList = Arrays.asList(
new Employee("xyz1", "abc", "address 1"),
new Employee("xyz123", "abc", "address 1"),
new Employee("xyz1234", "abc", "address 1")
);
public static void main(String[] args) {
Optional<String> longestName = findStringWithMaxLength(EmployeeField.NAME);
if (longestName.isPresent()) {
System.out.println("Longest name = " + longestName.get());
} else {
System.out.println("No longest name");
}
}
private static Optional<String> findStringWithMaxLength(EmployeeField employeeField) {
return employeeList.stream()
.map(employee -> employeeField.getGetter().apply(employee))
.max(Comparator.comparing(String::length));
}
EDIT for your city use case, something along those lines:
Add an enum AddressField on the same model as the EmployeeField
enum AddressField {
CITY(Address::getCity);
....
}
then add a method
private static Optional<String> findStringWithMaxLength(List<Address> addressList, AddressField addressField) {
return addressList.stream()
.map(employee -> addressField.getGetter().apply(employee))
.max(Comparator.comparing(String::length));
}
and then add a CITY enum to your EmployeeField enum:
LANDLINE_NUMBER(employee -> employee.getContactInfo().getLandlineNumber()),
CITY(employee -> findStringWithMaxLength(employee.getAddress(), AddressField.CITY).get());
I am creating Spring Boot Web service and I have a Model Employee
public class Employee {
private String id;
private String name;
private String designation;
private int salary;
//Has Getters and Setters
}
I want to create a Get request which will fetching and filter the List of Employees based on the parameters given by user.
For example, if the user gives name of an employee and designation of employee, the get method should filter those result. For various combination of parameters it should work.
#Override
public List<Employee> getEmployees(Map<String, Object> parameters) {
if (parameters.size() == 0)
// code to return all employees;
List<Employee> selectedEmployees = new ArrayList<Employee>();
for(Employee currentEmployee: new ArrayList<Employee>(employee.values())) {
for(Map.Entry<String, Object> check: parameters.entrySet()) {
try {
if(check.getValue() instanceof Integer) {
int condition = (int) Employee.class.getMethod("get" + check.getKey()).invoke(currentEmployee);
if((int) check.getValue() == condition)
selectedEmployees.add(currentEmployee);
} else if (check.getValue() instanceof String) {
String condition = (String) Employee.class.getMethod("get" + check.getKey()).invoke(currentEmployee);
if (((String) check.getValue()).equals(condition))
selectedEmployees.add(currentEmployee);
}
} catch(Exception e){
e.printStackTrace();
}
}
}
return selectedEmployees;
}
In order to avoid multiple if else cases I am filtering list based on String and Integer above.
I think I am making an error in the below code which sending request in Controller.
#RequestMapping(value={"/employees","/{id}/{name}/{designation}/{salary}"})
public List<Employee> getEmployeeByProperty(EmployeeRequestParameters requestParams){
//Map for storing parameters to filter the List
Map<String, Object> filterParams = new HashMap<>();
if(requestParams.getIdParam().isEmpty()) {
filterParams.put("id", Integer.parseInt(requestParams.getIdParam()));
}
if(!requestParams.getNameParam().isEmpty()) {
filterParams.put("name", requestParams.getNameParam());
}
if(!requestParams.getDesignationParam().isEmpty()) {
filterParams.put("designation", requestParams.getDesignationParam());
}
if(requestParams.getSalaryParam().isEmpty()) {
filterParams.put("salary", Integer.parseInt(requestParams.getSalaryParam()));
}
return EmployeeService.getEmployeesByProperty(filterParams);
}
If {id} field is not full, {name} or {designation} or {salary} to be null.For {name} or {designation} or {salary} to be full Because should be {id} full.
#GetMapping("/employees")
public List<Employee> getEmployeeByProperty(#RequestParam(value = "id", required=false) String id,
#RequestParam(value = "name", required=false) String name,
#RequestParam(value = "designation", required=false) String designation,
#RequestParam(value = "salary", required=false) int salary) {
//Your codes
}
Even if {id} is empty, you can use others.
I want to search value from object and convert result to list
I tried to get data object name "data" and i want to search every item that has "querytext".How to convert object data to List
public class SimpleMovieSearchService implements MovieSearchService {
#Autowired
private MovieDataService movieDataService;
#Override
public List<Movie> search(String queryText) {
MoviesResponse data =movieDataService.fetchAll();
List<Movie> result = data.stream() // problem in this line
.filter(item -> item.getTitle().equals("queryText"))
.collect(Collectors.toList());
return result;
}
}
MovieData.java
public class MovieData {
private String title;
private int year;
private List<String> cast;
private List<String> genres;
getter and setter
}
Movie.java
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ElementCollection(fetch = FetchType.EAGER)
private List<String> actors = new ArrayList<>();
getter and setter
}
edit
MovieResponse.java
public class MoviesResponse extends ArrayList<MovieData> {
}
MovieDataService.java
public interface MovieDataService {
MoviesResponse fetchAll();
}
Type of data i got is List of MovieData but i want result in List of Movie how to fix this or another way to do.and without change anything in Movie.java or MovieData.java
Update
now i can do with this way
MoviesResponse a = movieDataService.fetchAll();
List<Movie> result = a.stream()
.map(movie -> new Movie(movie.getTitle()))
.filter(movie -> movie.getName().equals(queryText)) //this line
.collect(Collectors.toList());
if data are "banana" ,"nature" , "red" and then query text is "na" i want result are "banana" and "nature".in sql in situation it can use "like".How to use "like" with this filter ?
Try to use stream map
data.stream() // problem in this line
.filter(item -> item.getTitle().equals("queryText"))
.map(movie -> {
//logic to transform MovieResponse in Movie here
})
.collect(Collectors.toList());
See more in: https://dzone.com/articles/how-to-use-map-filter-collect-of-stream-in-java-8
Instead of fetching all movies and filer them by stream, write a method that queries the ones you want.
Something like
SELECT * FROM movies WHERE title = 'queryText'
Depending on your code/framework, you have to implement this or just have to choose another method in you MovieDataService.
I need to filter elements and then sort based on certain column. Post that I would need to find the unique entries based on combination of columns. Since it is file processing, pipe(|) is used as delimiter to denote the column value.
String s1= "12|Thor|Asgaurd|1000000|Avenger|Active"
String s2= "234|Iron man|New York|9999999|Avenger|Active"
String s3= "420|Loki|Asgaurd|||Inactive"
String s4= "12|Thor|Asgaurd Bank|1000000|Avenger HQ|Active"
Data first needs to be filtered based on the Active/Inactive status. Then it needs to be sorted based on 4th column. Lastly, the uniqueness needs to be maintained by combining column 1,2,3.
Expected Output =
"234|Iron man|New York|9999999|Avenger|Active"
"12|Thor|Asgaurd|1000000|Avenger|Active"
Creating a model class and parsing the string is the way to go, but if for some reaseon you don't want to do that you can do it this way:
import java.util.Comparator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
List<String> result = Stream.of(s1, s2, s3, s4)
.filter(s -> s.split("\\|")[5].equals("Active"))
.sorted(Comparator.comparing(e -> e.split("\\|")[4]))
.collect(Collectors.toList());
First of all you should create an Object which represents your String data. Something like this:
public class MyObject {
private int id;
private String name;
private String location;
private Integer value;
private String category;
private String state;
public MyObject(String entry) {
String[] parts = entry.split("\\|");
if (parts.length != 6) {
throw new IllegalArgumentException("entry has not 6 parts");
}
id = Integer.parseInt(parts[0]);
name = parts[1];
location = parts[2];
try {
value = Integer.parseInt(parts[3]);
} catch (NumberFormatException ignored) {
}
category = parts[4];
state = parts[5];
}
// getters
#Override
public String toString() {
return String.join("|", String.valueOf(id), name, location, String.valueOf(value), category, state);
}
}
With this you can create a Stream of objects from your Strings and to the filter, sort and distinct operations afterwards:
Collection<MyObject> result = Stream.of(s1, s2, s3, s4)
.map(MyObject::new)
.filter(o -> "Active".equals(o.getState()))
.sorted(Comparator.comparing(MyObject::getValue).reversed())
.collect(Collectors.toMap(o -> Arrays.asList(o.getId(), o.getName()),
Function.identity(), (o1, o2) -> o1, LinkedHashMap::new))
.values();
result.forEach(System.out::println);
After the map operation you filter the values by state and sort them by column 4 (value in my case). At the end you collect all the values in a map for the distinct operation. Add all values you need distinction for to the Arrays.asList(). As values the map takes all the original values (Function.identity()). For duplicates we keep the first value ((o1, o2) -> o1) and we are using a LinkedHashMap to keep the order of the items. At the end wee use only the values of the map.
If you need a List instead of a Collection use new ArrayList(result).
The result will be this:
234|Iron man|New York|9999999|Avenger|Active
12|Thor|Asgaurd|1000000|Avenger|Active
It seems like you're unable to filter while everything is string only.
Try this,
create a new model class which can hold your columns.
Ex:
class MyData{
private String name;
private String city;
private String distance;
private String organization;
private String status;
//And create Getter Setter method for all above fields.
}
Now came to your main class where you can play with your code stuff.
Map<MyData> map = new HashMap<MyData>();
MyData myData = new MyData();
myData.setName("Thor");
myData.setCity("Asgaurd");
myData.setDistance("1000000");
myData.setOrganization("Avenger");
myData.setStatus("Active");
map.put(12, myData);
//Same thing for all other data (note: use the loop for data insertion in map)
Map<String, MyData> sorted = map.entrySet().stream().sorted(comparingByValue()).collect(toMap(e -> e.getKey(), e -> e.getValue().getName(), (e1, e2) -> e2,LinkedHashMap::new));
System.out.println("map after sorting by values: " + sorted);
You can solve your task this way:
Firstly, just create POJO(Plain Old Java Object) and override the toString() method.
class MarvelPerson {
private Integer id;
private String name;
private String origin;
private Integer point = null;
private String faction;
private String status;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
public Integer getPoint() {
return point;
}
public void setPoint(Integer point) {
this.point = point;
}
public String getFaction() {
return faction;
}
public void setFaction(String faction) {
this.faction = faction;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(id);
builder.append("|");
builder.append(name);
builder.append("|");
builder.append(origin);
builder.append("|");
if(point != null) {
builder.append(point);
}
builder.append("|");
if(faction != null) {
builder.append(faction);
}
builder.append("|");
builder.append(status);
return builder.toString();
}
}
Then, you should write the parser from string to MarvelPerson. Side note: Carefully, my implementation is pretty basic, and I suppose it should be modified because I may not have foreseen some corner cases.
class PersonParser {
static MarvelPerson parse(String data) {
MarvelPerson person = new MarvelPerson();
String[] array = data.split("\\|", -1);
person.setId(Integer.parseInt(array[0]));
person.setName(array[1]);
person.setOrigin(array[2]);
if(!array[3].isEmpty()) {
person.setPoint(Integer.parseInt(array[3]));
}
if(!array[4].isEmpty()) {
person.setFaction(array[4]);
}
person.setStatus(array[5]);
return person;
}
}
And then your solution:
public class Test {
public static void main(String[] args) {
List<MarvelPerson> list = new ArrayList<>();
list.add(PersonParser.parse("12|Thor|Asgaurd|1000000|Avenger|Active"));
list.add(PersonParser.parse("234|Iron man|New York|9999999|Avenger|Active"));
list.add(PersonParser.parse("420|Loki|Asgaurd|||Inactive"));
list.add(PersonParser.parse("12|Thor|Asgaurd Bank|1000000|Avenger HQ|Actie"));
list.stream()
.filter(marvelPerson -> marvelPerson.getStatus().equals("Active"))
.sorted((o1, o2) -> o1.getPoint() <= o2.getPoint() ? 1 : -1)
.forEach(marvelPerson -> {
System.out.println(marvelPerson.toString());
});
}
}
The output to be printed:
234|Iron man|New York|9999999|Avenger|Active
12|Thor|Asgaurd|1000000|Avenger|Active
I am using spring-boot-1.5.6 and modelmapper-1.1.0. I would like to map the entity object to OrderDto
but don't know how to do it via modelMapper. Please find the below code
Order.Java
public class Order {
private String orderUid;
private Invoice invoice;
private List<Item> items;
//Getter & setter
}
Item.java
public class Item {
private String itemId;
private String itemName;
private String itemUid;
private String isbn;
//other details of item
//Getter & setter
}
OrderDTO.java
public class OrderDTO {
private String orderUid;
private Invoice invoice;
private String itemId;
private String itemName;
private String itemUid;
private String isbn;
//other details of item
//Getter & setter
}
I would like to return OrderDTO with the item based on the itemID we are getting from the client(FrontEnd)
public Page<OrderDTO> convertOrderEntityToDTO (Page<Order> orderList,String itemId) {
ModelMapper modelMapper = new ModelMapper();
Type listType = new TypeToken<Page<OrderDTO>>() {}.getType();
modelMapper.addConverter((MappingContext<Order, OrderDTO> context) -> {
Item item = context.getSource().getItems().stream()
.filter(item -> equalsIgnoreCase(item.getItemId,itemId))
.findAny().orElse(null);
if (item != null) {
OrderDTO orderDTO = context.getDestination();
orderDTO.setItemId(item.getItemId());
orderDTO.setItemName(item.getItemName());
orderDTO.setItemUid(item.getItemUid());
orderDTO.setIsbn(item.getIsbn());
return orderDTO;
}
return null;
});
Page<OrderDTO> addonServices = modelMapper.map(orderList, listType);
}
In the above method, converter was never called(may be because of incorrect TypePair of modelMapper) and the item related attributes
in OrderDTO is always null. I would like to get the Item value based on ItemId.
Any help or hint would be appreciable. Any suggestion with or without modelMapper would be really appreciable.
As far as I understand, you use Page class of org.springframework.data or something like that. Anyway, this generic Page class contains generic List with your data. I would say, that this construction is just "too generic" for modelMapper. You'd better get list of your data, convert it and create a new Page.
Furthermore
You should create a typeMap to register a new converter
context.getDestination() returns not null if you provide new destination object by modelMapper.map(..). In your case you'll get null.
This is my vision of your convertOrderEntityToDTO method:
public Page<OrderDTO> convertOrderEntityToDTO(Page<Order> orderList, String itemId) {
ModelMapper modelMapper = new ModelMapper();
modelMapper.createTypeMap(Order.class, OrderDTO.class)
.setConverter(context -> context.getSource().getItems().stream()
.filter(o -> equalsIgnoreCase(o.getItemId(), itemId))
.findAny().map(o -> {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setItemId(o.getItemId());
orderDTO.setItemName(o.getItemName());
orderDTO.setItemUid(o.getItemUid());
orderDTO.setIsbn(o.getIsbn());
return orderDTO;
}).orElse(null));
List<OrderDTO> orderDtoList = orderList.getContent().stream()
.map(o -> modelMapper.map(o, OrderDTO.class))
.collect(Collectors.toList());
return new PageImpl<>(orderDtoList, orderList.getPageable(), orderList.getTotalElements());
}
If you are using Spring Data JpaRepositories to retrieve data from the database you can make a repository method that creates a DTO for you. Such a method would look something like this:
#Query("SELECT new full.path.OrderDTO(s.itemId, s.itemName, s.itemUid) FROM Item s WHERE s.itemId = :id")
public OrderDTO getOrderDTOByItemId(#Param("id") long id);
The method should go in the jparepository class you use to retrieve Item instances from the database with. To make this work your OrderDTO needs to have a constructor with this parameter list. ( long itemId, String itemName, String itemUid). The parameters need to be in the same order as (s.itemId, s.itemName, s.itemUid). Also always make sure you create a default constructor as well when you create a constructor with parameters.