Related
Suppose in this example, I have two object User and Address that is given below:
public User{
private String name;
private Address address;
// setter, Getter
}
public Address{
private String country;
// setter, Getter
}
I want to find the country from the user so I can simply use
user.getAddress().getCountry();
to get address with the help of method reference, It can be passed in parameter like
User::getAddress
but I have to find out the country name and I want to use in method reference way so how can I do?
You can write a utility function to compose two method references:
public class Foo {
static class AClass {
private final BClass b = new BClass();
public BClass getB() {
return b;
}
}
static class BClass {
public String getFoo() {
return "foo";
}
}
static <A,B,C> Function<A,C> compose(Function<A,B> ab, Function<B,C> bc) {
return ab.andThen(bc);
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
System.out.println(Optional.of(new AClass()).map(AClass::getB).map(BClass::getFoo));
System.out.println(Optional.of(new AClass()).map(compose(AClass::getB, BClass::getFoo)));
}
}
You cannot directly refer to getCountry () via User, but you can use stream to map to addresses and then reference getCountry ().
However, you should specify in what situation you want to use.
but e.g if you have a user list, you can do this:
List <User> users = List.of(
user,
user1);
users.stream()
.map(User::getAddress)
.map(Address::getCountry)
.forEach(System.out::println)
A simple way to compose multiple chained functions is to assign the first method reference to a local variable and apply .andThen(Other::ref):
Function<User, Address> user2Address = User::getAddress;
Function<User, String> user2Country = user2Address.andThen(Address::getCountry);
You can chain as many .andThen(Other::ref) as you need to reach the target mapping and use the combined function as one step in say 'stream.map` operations.
List.of(user1, user2,user3).stream()
.map(user2Country)
.forEach(System.out::println);
I don't want to use map() multiple times so I asked this question.
generally, I want to write a generic method where I get User or Address any properties by passing it from parameter, So I have used like given below:
private String getCountryName(User user, Function<? super User, String> mapper) {
return Optional.ofNullable(user)
.map(mapper)
.get();
}
Thanks for your great suggestion, andThen() is the way that I was wondering.
with the help this I can use like :
String username = getCountryName(vikash, User::getName);
Function<User, Address> getAddress = User::getAddress;
String countryName = getCountryName(vikash, getAddress.andThen(Address::getCountry));
public enum Test implements IsSerializable {
FOOD("FOOD", getFoodItems()),//---Getting Error here
HOTEL("HOTEL", getHotels());//---Getting Error here
private String name;
static final List<String> categories = new LinkedList<String>();
Test(String name) {
this.name = name;
}
public List<String> getCategories() {
return this.categories;
}
private List<String> getFoodItems(){
categories.add("Food item1");
categories.add("Food item2");
return categories;
}
private List<String> getHotels(){
categories.add("Hotel 1");
categories.add("Hotel 2");
return categories;
}
}
I am getting error while creating this Enum. I am new to this type Enum . Can anyone help to make this work?
3 main things:
1. getFoodItems() and getHotels() should be static.
The methods need the existing enum to exist and do not even use anything in the enum.
2. don't declare categories as a static attribute..
You use the same categories object(or references to the same object) because it is static. Remove the static keyword before it in order to make it a member attribute. Each object should have it's own list and this is not possible if it is static.
3. create the List inside the method and give it to the constructor
You call the constructor with 2 parameters: the name and the List but the constructor does only accept the name. Create the categories object inside the methand and return it to the constructor.
3 additional improvements from #Holger (see the comments)
4. Think twice before handing out references to mutable lists.
If you pass a mutable list to a method, that method can change the list which could lead to bugs that may be difficult to find.
5. The name is entirely obsolete as there is no getter for it and its value matches the intrinsic name() anyway.
You may want to add it in any case but enumerations already have a method name() that returns the name of the enum.
6. Don’t use LinkedList when you don’t need its special features (in other words, never use it), but rather, use an ArrayList or even better, List.of(item1, item2), to create an immutable list.
ArrayList is more performant that LinkedList in general because it is based on an array and LinkedList is a linked list(as the name says) that has to create an object for every element containing reference to it's neighbours. That is an advantage if you need to add elements in the middle (or the start) of the list or if you need Queue or Dequeue functionality.
public enum Test implements IsSerializable {
FOOD("FOOD",getFoodItems()),//---Getting Error here.
HOTEL("HOTEL",getHotels());//---Getting Error here
private String name;
private final List<String> categories;
private Test(String name,List<String> categories) {
this.name = name;
this.categories=categories;
}
public List<String> getCategories() {
return this.categories;
}
private static List<String> getFoodItems(){
List<String> categories = new LinkedList<>();
categories.add("Food item1");
categories.add("Food item2");
return categories;
}
private static List<String> getHotels(){
List<String> categories = new ArrayList<>();
categories.add("Hotel 1");
categories.add("Hotel 2");
return categories;
}
}
[Edit]
Please also take note of the answer from boot-and-bottet
Static methods should work, if the constructor is fixed. If the list of items is small, why not declare them inline?
public static enum Test implements IsSerializable {
FOOD("FOOD", "Food item1", "Food item2"),
HOTEL("HOTEL", "Hotel 1", "Hotel 2");
private final String displayName;
private final List<String> categories;
Test(String displayName, String... categories) {
this.displayName = displayName;
this.categories = List.of(categories);
}
public String displayName() {
return displayName;
}
public List<String> getCategories() {
return categories;
}
}
Core issue is that enum initialized in static, and from that context you can't reference non-static items (fields, methods).
Also you don't have place for those lists in your enum - constructor accepts only name param.
You could try to use List.of("Food item1", "Food item2") instead for example and adding new field.
I'm writing a program now in Java which is kind of like a server. I got a MemberController, in MemberController it gets Members from the database OR from the cache (to speed up process). This is an example of how it looks:
public class MemberController {
private final TMap<Integer, Member> members;
public MemberController() {
this.members = new THashMap<>();
}
public Member getMemberByID(int id) {
if (members.containsKey(id)) {
return members.get(id);
}
// GET DATA FROM DB
members.put(ID, MEMBER);
return MEMBER;
}
Now, Member contains a BadgeController object, which contains a TMap for the badges. Example of Member:
public class Member {
// FIELDS OF MEMBER HERE
private BadgeController badgeController;
public Member(ResultSet set) {
// SET FIELDS
}
public void InitOtherData() {
badgeController = new BadgeController(id);
}
public BadgeController getBadgeController() {
return badgeController;
}
And BadgeController:
public class BadgeController {
private final int memberId;
private final TMap<String, Badge> badges;
public BadgeController(int memberId) {
this.memberId = memberId;
this.badges = new THashMap<>();
// LOAD FROM DB
}
public Badge getBadge(String code) {
return badges.get(code);
}
Now, I was wondering a few things (all actually refer to the same I guess):
If I get a Member from members, like members.get(1), and I edit the object, like this:
Member member = members.get(1);
member.setId(1);
Will this edit the id inside the TMap as well? So if I do members.get(1) again, it has the updated value?
If I have the member from above, and I change a value of the Badge, for example I do:
Member member = members.get(1);
member.getBadgeController().getBadge('500Members').setActive(true);
Will this result in true being printed?
System.out.println(members.get(1).getBadgeController().getBadge('500Members').getActive());
I hope my explaination is good enough. It's hard for me to explain it. I'm sorry.
Member member = members.get(1); does not copy the object but just makes a shortcut (reference). Changing member affects the item in your set as well.
To create an effective copy you have to make your object inherit from the Cloneable interface and call the clone() method on it to get a copy.
you need to DEEP copy object by:
implementing clone interface
create a copy constructor (simplest solution as clone)
examples:
// simple copy constructor
public SomerController(SomeController original) {
members = orginal.clone();
}
// more advanced copy constructor
public SomeController(SomeController original) {
Set<Map.Entry<String, String>> entries = orginal.members.entrySet();
members = new HashMap<String,Class>();
Iterator<Map.Entry<String, Class>> iterator = entries.iterator();
while(iterator.hasNext()) {
Map.Entry<String, String> next = iterator.next();
String key = next.getKey();
// if class contains a collections ( maps, arrays )
// you need to provide a copy here
// ensure to copy whole tree of references
Class value next.getValue();
map.put(key,value);
}
}
I have multiple methods in a Java class where every method has 20+ parameters. I will create an object for this class in another class and call each and every method. Typically I'm using the POM (Page Object Model) in Selenium Java.
So in every Page object class, there are multiple(20+) parameters in every method, which I will call in the Test Class.
Page Object Class :
public void enterShipInfo(String IMO,String Vstat,String Vcode,String Vname,
String Vtype,String Officialno,String Buildyr,String Shipyard,String Hullno,String Layingdate,
String Launcheddate,String Deliverdate,String Reportinclude,String Portregistry,String VFlag,
String Vstatus,String Classification,String Classid,String Classnotation,String PI,String HM,
String Regowner,String Shipmanager,String Comoperator,String Callsign,String SSR,String Factor,
String ELOG,String Vcomments,String VsisIMO,String Chartertype,String Showonweb){
}
.... Other Methods with similar long list of parameters
Then in Test Class, again I'm creating parameters for these:
public class VesTest {
#Test(dataProvider="Ves",priority=1)
public void createVesTest(String IMO,String Vstat,String Vcode,String Vname,
String Vtype,String Officialno,String Buildyr,String Shipyard,String Hullno,String Layingdate,
String Launcheddate,String Deliverdate,String Reportinclude,String Portregistry,String VFlag,
String Vstatus,String Classification,String Classid,String Classnotation,String PI,String HM,
String Regowner,String Shipmanager,String Comoperator,String Callsign,String SSR,String Factor,
String ELOG,String Vcomments,String VsisIMO,String Chartertype,String Showonweb
Mdr_Vessel obj_Mdr_Vessel = page(Mdr_Vessel.class);
obj_Mdr_Vessel.clickSubmenu();
.....
}
Any efficient way to reduce typing the parameters again in Test Class???
I don't want to break the method into multiple methods. So please suggest me a way of passing parameters in an efficient way
You can create new objects to group your parameters and then use them in your method signature.
For example :
public class VParameter {
String Vstat;
String Vcode;
String Vname;
String Vtyp;
I don't know if this counts as "breaking up the method into multiple methods", but what you can do is collect the parameters in a single object. Then for example
void method(Type1 parameter1, Type2 parameter2, Type3 parameter3) { ... }
becomes:
public class Parameters {
private Type1 parameter1;
private Type2 parameter2;
private Type3 parameter3;
// getters and setters
}
void method(Parameters params) { ... }
This kind of pattern is often used in a fluent style:
public class Parameters {
private Type1 parameter1 = /* convenient default value */;
private Type2 parameter2 = /* convenient default value */;
private Type3 parameter3 = /* convenient default value */;
public Parameters setParameter1(Type1 parameter1) {
this.parameter1 = parameter1;
return this;
}
// other setters in the same style and getters
}
Then you can call your method like:
method(new Parameters().setParameter1(...).setParameter3(...));
(where you only set the parameters with non-default values).
Can you create a class to regroup all parameters ?
You should read about the Prameter object patter which deals with that type of problem. In brief, it suggests you to crate a wrapper object for all parameters that the method accepts and use it instead the long list of arguments.
public class YourClassName {
private String IMO;
private String Vstat;
private String Vcode;
// other parameters
public YourClassName(String IMO, String Vstat, String Vcode, /* other params*/) {
this.IMO = IMO;
this.Vstat = Vstat;
this.Vcode = Vcode;
// assign other params
}
/getters
}
You can use the builder factory pattern https://jlordiales.wordpress.com/2012/12/13/the-builder-pattern-in-practice/
I have a below class and i need to get field name from getter method using java reflection.
Is it possible to get field name or property name using getter method?
class A {
private String name;
private String salary;
// getter and setter methods
}
My questions is: can i get field/property name by getter method? If I use getName(), can I get name property? I need name property but not its value. Is it possible through java reflection?
yes it's 100% possible..
public static String getFieldName(Method method)
{
try
{
Class<?> clazz=method.getDeclaringClass();
BeanInfo info = Introspector.getBeanInfo(clazz);
PropertyDescriptor[] props = info.getPropertyDescriptors();
for (PropertyDescriptor pd : props)
{
if(method.equals(pd.getWriteMethod()) || method.equals(pd.getReadMethod()))
{
System.out.println(pd.getDisplayName());
return pd.getName();
}
}
}
catch (IntrospectionException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
The reflection-util library provides a way to determine the property (name) in a type-safe manner.
For example by using the getter method:
String propertyName = PropertyUtils.getPropertyName(A.class, A::getSalary);
The value of propertyName would be "salary" in this case.
Disclaimer: I’m one of the authors of the reflection-util library.
You cannot inspect what code does by using reflection.
You can assume that a getName() method read a field called name and does nothing else. However there is no requirement for it to so. e.g. the field name might be m_name or _name or nameField or not even be a field.
It's not exactly good enough to just remove the "get" or "is" prefix and lower case the first letter. For example, the appropriate bean name for getID would be ID and not iD.
The easiest way to get the bean name is to lop off the get or is prefix and then pass the result into Introspector.decapitalize.
Here's a method I wrote to do this very thing:
private String getBeanName(String methodName)
{
// Assume the method starts with either get or is.
return Introspector.decapitalize(methodName.substring(methodName.startsWith("is") ? 2 : 3));
}
You can use lombok's #FieldNameConstants annotation.
Annotate your class:
import lombok.experimental.FieldNameConstants;
import lombok.AccessLevel;
#FieldNameConstants
public class FieldNameConstantsExample {
private final String name;
private final int rank;
}
which produces following code on the background:
public class FieldNameConstantsExample {
private final String name;
private final int rank;
public static final class Fields {
public static final String name = "name";
public static final String rank = "rank";
}
}
So you can access property name in a following way:
FieldNameConstantsExample.Fields.name
which is string "name"
You can
Field[] declaredFields = A.class.getDeclaredFields();
for(Field f:declaredFields){
System.out.println(f.getName());
}
If your bean's follow JavaBean conventions then you use reflection to get all the "get" and "is" methods and remove "get" or "is" prefixes from the retrieved method names and you have the field names.
Update
// Get the Class object associated with this class.
MyClass myClass= new MyClass ();
Class objClass= myClass.getClass();
// Get the public methods associated with this class.
Method[] methods = objClass.getMethods();
for (Method method:methods)
{
String name=method.getName();
if(name.startsWith("get") || name.startsWith("is"))
{
//...code to remove the prefixes
}
}
Using reflections API, POJO fields can be retrieved as below. Inherited class may find an issue here.
TestClass testObject= new TestClass().getClass();
Fields[] fields = testObject.getFields();
for (Field field:fields)
{
String name=field.getName();
System.out.println(name);
}
Or by using Reflections API, one can also retrieve all methods in a class and iterate through it to find the attribute names (standard POJO methods start with get/is/set) ... This approach worked for me for Inherited class structure.
TestClass testObject= new TestClass().getClass();
Method[] methods = testObject.getMethods();
for (Method method:methods)
{
String name=method.getName();
if(name.startsWith("get"))
{
System.out.println(name.substring(3));
}else if(name.startsWith("is"))
{
System.out.println(name.substring(2));
}
}
However a more interesting approach is below:
With the help of Jackson library, I was able to find all class properties of type String/integer/double, and respective values in a Map class. (all without using reflections api!)
TestClass testObject = new TestClass();
com.fasterxml.jackson.databind.ObjectMapper m = new com.fasterxml.jackson.databind.ObjectMapper();
Map<String,Object> props = m.convertValue(testObject, Map.class);
for(Map.Entry<String, Object> entry : props.entrySet()){
if(entry.getValue() instanceof String || entry.getValue() instanceof Integer || entry.getValue() instanceof Double){
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
}
You should access through the method. At the moment the getter would return the member name, but that could change in the future. It could lazily instantiate this from a database or webservice, built it from a firstname/surname etc. The name field could quite likely not exist.
So always go through the method (even via reflection)
If you know the name of the method, you only need to remove "get" and convert to lower letter the following letter, so you don´t need reflection.
If the getter method (getName()) returns a property with different name than "name", you can´t obtain the property's name from the method´s name.
If you don´t know the name of the method, by reflection you can obtain all methods and you can obtain all name´s properties too.
Try the following
class A{
private String name;
private String salary;
//getter and setter methods
public void setName(String name){
this.name = name;
}
public void setSalary(String salary){
this.salary = salary;
}
public String getName(){
return name;
}
public String getSalary(){
return salary;
}
}
The get method is used to retrieve data dynamically from program method or from database. It will reflect only values not property of the value.