Iterate through elements of List - Java 8 - java-8

I have a List of String, i need to iterate elements and create a new Object for each element in the list and add to a parent list, how do ido in Java 8 , this is what i tried so far:
List<CustomObject> parentList = new ArrayList<>();
List<String> emailList = fromSomeMethod();
emailList().stream().forEach(email -> parentList.add(new CustomObject(email)));
I am getting an error:
"variable used in lambda expression should be final or effectively final"
Any suggestions ? dont want to do it in the old school way,
Thanks,

List<CustomObject> parentList = emailList().stream()
.map(CustomObject::new)
.collect(Collectors.toList());
No need to complicated things, just map that and collect to a new List

Try like this You should have Parameterized Constructor
public class CustomObject {
private String email;
private boolean isFlag;
//Getter setter
public CustomObject(String email, boolean isFlag) {
this.email = email;
this.isFlag = isFlag;
}
public CustomObject(String email) {
this.email = email;
}
}
List<CustomObject> parentList = emailList.stream().map(CustomObject::new).collect(Collectors.toList());

Use this:
static class CustomObject {
String email;
public CustomObject(String email) {
this.email = email;
}
}
private static void test4() {
List<CustomObject> parentList = new ArrayList<>();
List<String> emailList = Arrays.asList("aa#gmail.com", "bb#yahoo.com");
emailList.stream()
.map(CustomObject::new)
.forEach(parentList::add);
}

Related

Android room. error: Cannot figure out how to read this field from a cursor

the SQLite database contains three tables 1) employee 2) skills 3) departments. The idea is this - the employee table stores data such as id, name, last_name, salary. Also, an employee has data such as skill and department, but there can be several data for one employee, so I created two separate skills and departments tables and linked them using the key to the employee table where the primary key for employee is id. Now with the help of id I need to display all the information about employee including his skills which can be several and departments. I implement the whole process using the ROOM library.
Here is the request I make
#Query("SELECT employ.id ,employ.name ,employ.last_name, employ.salary, " +
"skill.skill, department.department_name FROM employ INNER JOIN skill,department " +
"ON employ.id = :id AND skill.employ_id = :id AND department.employ_id = :id ")
AllAboutEmployee getAllAboutEmployee(String id);
Here is the AllAboutEmployee class whose object accepts the result of the request
public class AllAboutEmployee {
#ColumnInfo(name = "id")
private String id;
#ColumnInfo(name = "name")
private String name;
#ColumnInfo(name = "last_name")
private String lastName;
#ColumnInfo(name = "salary")
private String salary;
#ColumnInfo(name = "department_name")
private List<String> departmentsList; // THE ERROR IS ON THIS LINE
#ColumnInfo(name = "skill")
private List<String> skillList; // THE ERROR IS ON THIS LINE
public AllAboutEmployee(String id, String name, String lastName, String salary, List<String> departmentsList, List<String> skillList) {
this.id = id;
this.name = name;
this.lastName = lastName;
this.salary = salary;
this.departmentsList = departmentsList;
this.skillList = skillList;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getSalary() {
return salary;
}
public void setSalary(String salary) {
this.salary = salary;
}
public List<String> getDepartmentsList() {
return departmentsList;
}
public void setDepartmentsList(List<String> departmentsList) {
this.departmentsList = departmentsList;
}
public List<String> getSkillList() {
return skillList;
}
public void setSkillList(List<String> skillList) {
this.skillList = skillList;
}
}
So ther are two fields int the AllAboutEmployee class with the List type, in order to put several skills and several departments there. It is in these fields that an error occurs. Thank you in advance for your help
Wow.. that's so cool.. I was coding all day and got this error too!
You have to create a TypeCoverter to store your data into your Room's Database.
In this case you have two List, that are not types recognizable by Database, so you have to create an Converter for it to store as a String, and another method to do the inverse.
Something like:
class TypeCoverter{
#TypeConverter
fun arrayListToString(arrayList: ArrayList<String>?): String? {
if (arrayList.isNullOrEmpty()) return null
val string = StringBuilder()
for (item in arrayList) {
val isNotTheLastItemInTheArrayList = (item == arrayList.last()).not()
if (isNotTheLastItemInTheArrayList) {
string.append(item).append(COMMA)
} else {
string.append(item)
}
}
return string.toString()
}
}
#TypeConverter
fun stringToArrayList(string: String?): ArrayList<String>? {
when {
string.isNullOrEmpty() -> {
return null
}
string.contains(COMMA).not() -> {
val list = ArrayList<String>()
list.add(string)
return list
}
else -> {
return string.split(COMMA.toRegex()).dropLastWhile { it.isEmpty() } as ArrayList<String>
}
}
}
That's actually in Kotlin, but you can see how it works.

Generic Search and Filter by dynamic fields for Criteria (Global Search)

I have a scenario where I need to add Criteria to perform search and filter in Spring using mongoTemplate.
Scenario:
Lets say I have Student, Course and PotentialStudent. and I have to define only certain fields to be used for search and filter purpose. For PotentialStudent, it contains both Student and Course information that is collected before all required information is gathered to be filled to Student and Course.
Search Fields are the fields to be used for searching either of the fields. For example: get values matching in either courseName or courseType in Course.
Filter is to be used to filter specific fields for matching multiple values and the values to be filtered on field is set on FilterParams. Meaning, if I get values in FilterParams.studentType then for PotentialStudent I should
add Criteria to search inside PotentialStudent's student.type for list of values whereas if for Student add Criteria to search in Student's type.
public abstract class Model {
#Id
protected String id;
#CreatedDate
protected Date createdDateTime;
#LastModifiedDate
protected Date modifiedDateTime;
protected abstract List<String> searchFields();
protected abstract Map<String, String> filterFields();
}
#Getter
#Setter
#Document("student")
public class Student extends Model {
private String firstName;
private String lastName;
private String address;
private StudentType type;
#Override
protected List<String> searchFields() {
return Lists.newArrayList("firstName","lastName","address");
}
#Override
protected Map<String, String> filterFields() {
Map<String, String> filterMap = Maps.newHashMap();
filterMap.put("studentType", "type");
return filterMap;
}
}
#Getter
#Setter
#Document("course")
public class Course extends Model {
private String courseName;
private String courseType;
private int duration;
private Difficulty difficulty;
#Override
protected List<String> searchFields() {
return Lists.newArrayList("courseName","courseType");
}
#Override
protected Map<String, String> filterFields() {
Map<String, String> filterMap = Maps.newHashMap();
filterMap.put("courseDifficulty", "difficulty");
return filterMap;
}
}
#Getter
#Setter
#Document("course")
public class PotentialStudent extends Model {
private Student student;
private Course course;
#Override
protected List<String> searchFields() {
return Lists.newArrayList("student.firstName","student.lastName","course.courseName");
}
#Override
protected Map<String, String> filterFields() {
Map<String, String> filterMap = Maps.newHashMap();
filterMap.put("studentType", "student.type");
filterMap.put("courseDifficulty", "course.difficulty");
return filterMap;
}
}
}
public class FilterParams {
private List<StudentType> studentTypes;
private List<Difficulty> difficulties;
}
public class PageData<T extends Model> {
public void setPageRecords(List<T> pageRecords) {
this.pageRecords = pageRecords;
}
private List<T> pageRecords;
}
//Generic Search Filter Implementation Class
public class GenericSearchFilter {
public <T extends Model> PageData getRecordsWithPageSearchFilter(Integer page, Integer size, String sortName, String sortOrder, String value, FilterParams filterParams, Class<T> ormClass) {
PageRequestBuilder pageRequestBuilder = new PageRequestBuilder();
Pageable pageable = pageRequestBuilder.getPageRequest(page, size, sortName, sortOrder);
Query mongoQuery = new Query().with(pageable);
//add Criteria for the domain specified search fields
Criteria searchCriteria = searchCriteria(value, ormClass);
if (searchCriteria != null) {
mongoQuery.addCriteria(searchCriteria);
}
//Handle Filter
query.addCriteria(Criteria.where(filterFields().get("studentType")).in(filterParams.getStudentTypes()));
query.addCriteria(Criteria.where(filterFields().get("courseDifficulty")).in(filterParams.getDifficulty()));
List<T> records = mongoTemplate.find(mongoQuery, ormClass);
PageData pageData = new PageData();
pageData.setPageRecords(records);
return pageData;
}
private <T extends BaseDocument> Criteria searchCriteria(String value, Class<T> ormClass) {
try {
Criteria orCriteria = new Criteria();
if (StringUtils.isNotBlank(value)) {
BaseDocument document = ormClass.getDeclaredConstructor().newInstance();
Method method = ormClass.getDeclaredMethod("searchFields");
List<String> records = (List<String>) method.invoke(document, null);
Criteria[] orCriteriaArray = records.stream().map(s -> Criteria.where(s).regex(value, "i")).toArray(Criteria[]::new);
orCriteria.orOperator(orCriteriaArray);
}
return orCriteria;
} catch (Exception e) {
log.error(e.getMessage());
}
return null;
}
}
Given this scenario, my question is how to handle filter cases in better and dynamic way and how to implement a Global search if needed to search in all Document types for specified fields on each types.

Cannot remove attributes in ldap with spring ldap

we need to make a spring boot project that works with spring ldap.
every things is good.But when we remove a member from a group,the member deleted form group (i see it in debug mode in a Setmembers) but, in ldap(Oracle Internet Directory) that member exists!
Please help me!
//Group Entry
#Entry(objectClasses = {"top", "groupOfUniqueNames", "orclGroup"}, base = "cn=Groups")
public final class Group {
#Id
private Name dn;
#Attribute(name = "cn")
private String name;
private String description;
private String displayName;
#Attribute(name = "ou")
private String ou;
#Attribute(name = "uniqueMember")
private Set<Name> members;
public void addMember(Name newMember) {
members.add(newMember);
}
public void removeMember(Name member) {
members.remove(member);
}
//Custom LdapUtils
public class CustomLdapUtils {
private static final String GROUP_BASE_DN = "cn=Groups";
private static final String USER_BASE_DN = "cn=Users";
public Name buildGroupDn(String name) {
return LdapNameBuilder.newInstance(GROUP_BASE_DN)
.add("cn","Charts")
.add("cn",name)
.build();
}
private static final CsutomLdapUtils LDAP_UTILS = new CsutomLdapUtils ();
private CsutomLdapUtils () {
}
public Name buildPersonDn(String name) {
return LdapNameBuilder.newInstance(USER_BASE_DN)
.add("cn", name)
.build();
}
}
//Controller
#DeleteMapping(value = "/memberOfGroup", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> removeMemberFromGroup(#RequestBody Map<String,String> map) throws NamingException {
List<Group> groupToFind = ldapSearchGroupsService.getGroupByCn(map.get("groupName"));
List<User> userToFind = ldapSearchUserService.getAllUserByUserName(map.get("userName"));
if (groupToFind.isEmpty()) {
//TODO : Group no found!
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
for (Group group1 : groupToFind) {
group1.removeMember(userToFind.stream().findAny().get().getDn());
//ldapBindGroupService.deleteMemberFromGroup(group1);
DirContextOperations ctx = ldapTemplate.lookupContext(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")));
ctx.removeAttributeValue("uniqueMember",map.get("userName"));
ctx.rebind(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")),map.get("groupName"));
ldapTemplate.modifyAttributes(ctx);
}
return new ResponseEntity<>(HttpStatus.OK);
}
}
Is some problem in code? or need some methods?
Finally after several search and debug,i found the problem!
In each ldap env,after every changes,the directory must be commit and apply.
In above code,i implemented that,but not in true way!
Best way is here:
#DeleteMapping(value = "/membersOfGroup", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> removeMemberFromGroup(#RequestBody Map<String,String> map) {
List<Group> groupToFind = ldapSearchGroupsService.getGroupByCn(map.get("groupName"));
List<User> userToFind = ldapSearchUserService.getAllUserByUserName(map.get("userName"));
if (groupToFind.isEmpty()) {
//TODO : Group no found!
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
for (Group group1 : groupToFind) {
group1.removeMember(userToFind.stream().findAny().get().getDn());
DirContextOperations ctx = ldapTemplate.lookupContext(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")));
ctx.removeAttributeValue("member",CustomLdapUtils.getInstance().buildPersonDn(map.get("userName")));
//True way
ldapTemplate.update(group1);
}
return new ResponseEntity<>(HttpStatus.OK);
}
}

Relationship Exists in neo4j but not in Spring #NodeEntity

I have a class in my domain called Activity that looks like the following
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
#NodeEntity
public class Activity {
#GraphId
private Long id;
private String title;
private String description;
#Relationship(type = "RELATED_TO", direction = Relationship.UNDIRECTED)
private List<Activity> relatedActivities = new ArrayList<>();
public Activity() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
public Collection<Activity> getRelatedActivities() {
System.out.println("getting relatedActivities");
System.out.println(relatedActivities);
return relatedActivities;
}
public void addRelatedActivity(Activity activity) {
this.relatedActivities.add(activity);
}
}
I create relationships using the following repository class:
#RepositoryRestResource(collectionResourceRel = "relationships", path = "relationships")
public interface RelationshipRepository extends GraphRepository<Relationship> {
#Query("MATCH (a1:Activity), (a2:Activity) " +
"WHERE a1.title = {0} AND a2.title = {1}" +
"CREATE (a1)-[:RELATED_TO]->(a2)")
void addRelationship(String a1Title, String a2Title);
}
I have verified that this code works using the neo4j browser, which lets me see existing nodes and relationships between them. However, when I access getRelatedActivities() on an Activity object, it's always an empty array, even if that Activity has other Activity nodes related to it, clearly visible in neo4j.
How can I get the relatedActivites on an Activity to automatically populate based on its relationships correctly?
The problem in your code is that you define the "target" as an Activity here
#Relationship(type = "RELATED_TO", direction = Relationship.UNDIRECTED)
private List<Activity> relatedActivities = new ArrayList<>();
but you also have a RelationshipEntity class in your code base: Relationship with the same type RELATED_TO.
When OGM gets the result it tries to match every field but since it converts the relationship type RELATED_TO to the RelationshipEntity and not an Activity object, it does not fill the list in the Activity class.

How can I get multiple properties from a Java POJO using the Java 8 Stream API?

Given this class written in the Java 8 style, I wanted to see if I dont need to call the stream api twice :
import java.util.*;
public class Foo {
public static void main(String... args) {
List<Person> persons = new ArrayList<>();
init(persons, Person::new, "John", "Doe");
persons.stream()
.map(Person::getFirstName)
.forEach(System.out::println);
persons.stream()
.map(Person::getLastName)
.forEach(System.out::println);
}
#FunctionalInterface
interface PersonFactory {
Person create(String firstName, String lastName);
}
private static void init(List<Person> persons, PersonFactory factory, String fn, String ln) {
persons.add(factory.create(fn, ln));
}
}
class Person {
private final String firstName;
private final String lastName;
public Person(String fName, String lName) {
this.firstName = fName;
this.lastName = lName;
}
public String getFirstName() {return this.firstName;}
public String getLastName() {return this.lastName;}
}
I wanted to see if I could instead stream the "persons" List in one go.
Any suggestions ?
If you don't need to transform object to another, you can try this
persons.forEach(i -> System.out.println(i.getFirstName() + " " + i.getLastName()));
i think it could be helpfull for you using Map
Map<String, String> mapp = persons.stream().collect(HashMap::new,
(m, c) ->{
m.put(c.getFirstname(), "");
m.put(c.getLastname(), "");
},HashMap::putAll);
System.out.println(mapp.keySet().toString());

Resources