I was looking arround for this, but I couldn´t find a right answer.
I´m trying to get any field from an entity based on it´s column name.
Like a generic get, in which it receives a String columnName and returns an Object field that represents the Class field which is mapped by that columnName by Hibernate.
For example
#Table(name="ENTITY_EXAMPLE")
public class EntityExample{
#Column(name="COL_NAME")
private String name;
#Column(name="COL_SURNAME")
private String surname;
public EntityExample(String name, String surname){
this.name=name;
this.surname=surname;
}
//getters and setters
public Object getField(String columnName){
Object field=//some way to map the columnName with the field;
return field;
}
}
public main(String[] args){
EntityExample example=new EntityExample("John", "Doe");
String exampleName=(String) example.getField("COL_NAME");
String exampleSurname=(String) example.getField("COL_SURNAME");
System.out.println("NAME: "+ exampleName+ ", SURNAME: "+exampleSurname);
}
and that main when runs should print:
NAME: John, SURNAME: Doe
The way I´m doing now is with ifs that checks if the parameter is equal to each annotated column and inside returns the field if equals, but it should be a propper way to do that.
way I'm doing now:
public Object getField(String columnName){
if(columnName.equals("COL_NAME")){
return name;
}
if(columnName.equals("COL_SURNAME")){
return surname;
}
}
Thanks in advance.
As far as I know, the way you're doing it, is the only way. With the exception being, to use a switch statement instead of multiple if statements:
switch (columnName) {
case 1: columnName = "COL_NAME";
return this.name;
break;
case 2: columnName= "COL_SURNAME";
return this.surname;
break;
default: columnName= "COL_BLAHBLAH";
return this.blahblhblah;
break;
}
The only possible way to what you want (and this is a big stretch), is if you did something along the lines of:
public Object getField(String columnName){
Object field= (Object)columnName;
return field;
}
Note: You would need to pass in the object name (aka: name,surname) and not the column name.
But I honestly don't think this is going to work. Regardless, you would need to cast a string as an object in such a way that the compiler would know how to handle the casting properly (don't think it's possible).
Good luck either way. Maybe someone else will have more ideas.
You can , of course, use reflection to go through the fields of your entity, looking for which one has the #Column annotation with the corresponding name. However, many people will tell you that Reflection is slow.
What we did to accomplish this was to create a set of public static integer constants for each of the columns. Thus in your entity you would have the following:
public static final int COL_NAME = 1;
public static final int COL_SURNAME = 2;
and in the Entity you also have a getFieldValue method as follows:
public Object getFieldValue(int fieldNo) {
switch (fieldNo) {
case COL_NAME:
return this.name;
case COL_SURNAME:
return this.surname;
default:
throw IllegalArgumentException("Invalid Field Number: " + fieldNo);
}
}
and you would use these to get fields values as follows:
String name = entityExample.getFieldValue(EntityExample.COL_NAME);
Of course, the problem you have now is maintaining both the list of constants and the switch cases when columns are added/removed/renamed. We get round this by using a script to generate both the constants and the method. You could also use Java's annotation processing to generate the same code.
Related
I have an enum with enum values. I want to print the list of the enum values only.
Not just the enum. I have read about Value Of but see thats not the correct way to go at it.
This is what I want printed:
People Out
People In
Here is my enum with values in it. I added a constructor.
public enum People {
OUT("People out"),
IN("People in");
private final String name;
People(String name) {
this.name = name;
}
}
The method to retrieve the enums is:
public String retrieveEnumValues() {
return Stream.of(People.values()).
map(People::name).collect(Collectors.joining("\n"));
}
What am I doing wrong here?
People::name refers to standard enum's method name(), you should provide getter for your name field and using it People::getName.
I have to do a little exercise (homework, like a friendlist) in Java, and i'm a little stuck on one of the tasks that i have to implement in my program.
The exercise is about storing some friend-objects with a variety of attributes in a container-class and implementing some methods in the container-class for various tasks on the friend-objects.
The overall exercise is not a problem at all, but i'm quite unconvinced that my solution is the way to go. I hope you can give me some tips here.
The method that is left over, should be something like a "updateFriend" method, with which you can set the value of a given attribute to a new value, straight from the container-class.
I've already set up my friend-class with a handfull of attributes (e.g. prename, lastname, date of birth, adress, and so on) an getters/setters for all of them. I've also implemented the container-class (as an ArrayList), but i can't seem to find an elegant way to implement this specific method. My updateFriend()-method right now takes three parameters.
1.The specific id of the friend-object
2.The name of the attribute that i want to change
3.The new value of the attribute
It uses an enum to check if the entered attribute is an existing attribute and if yes, the method searches the ArrayList for the object that contains that attribute and should overwrite the existing value. It gets a little bulky, as i have implemented a switch on the enum, that calls the fitting setter-method for each attribute of the friend, if the type in attribute exists at all.
So basically the friend-class looks like this:
public class Friend {
private static int friendCount = 1;
private String firstname;
private String lastname;
private LocalDate dateOfBirth;
private String phonenumber;
private String mobilenumber;
private String eMail;
private Adress home;
private int friendID;
//Getters & Setters
...
}
The method that gives me problems in the container-class looks something like this at the moment:
public void updateFriend(int id, String toChange, String newValue)
{
for(Attribute a : attribute.values())
{
if(String.valueOf(a).equalsIgnoreCase(toChange))
{
for(Friend f : friends)
{
int counter = 1;
if(f.getID() == id)
{
switch(a)
{
case FIRSTNAME:
{
f.setPreName(neuerWert);
break;
}
//a case for each attribute
}
I'm quite certain that my take on the given method is messy, slow, and cumbersome. What would be an elegant way of solving this?
Excuse my wording and thanks in advance, greets.
I would suggest 3 performance improvements.
Use HashMap instead of List with key as id. Since, id will be unique, it will take O(1) time to get the relevant object for modification instead of spending O(n) time on List iteration.
You can change the type of toChange parameter from String to enum. This will avoid enum to String conversion and then comparing it.
Since, you are already doing validation of the attribute to be modified and you must be following standard java convention while naming your getters and setters, you can use reflection to call the method on the Friend object by creating the method name from attribute name like set{Attributename}.
Okay, lets start using the enum Attribute to handle all the changes (Since you already holding the attribute values)
Attribute Enum
public enum Attribute {
FIRSTNAME("fname", (friend, name) -> friend.setFirstname(String.valueOf(name))),
LASTNAME("lname", (friend, lname) -> friend.setLastname(String.valueOf(lname))),
DATEOFBIRTH("dob", (friend, dob) -> friend.setDateOfBirth((LocalDate) dob)),
PHONENUMBER("pno", (friend, pno) -> friend.setFirstname(String.valueOf(pno))),
MOBILENUMBER("mno", (friend, mno) -> friend.setFirstname(String.valueOf(mno)));
private String attributeName;
private BiConsumer<Friend, Object> attributeSetter;
public static Attribute getAttributeSetterByName(String attributeName) {
return Arrays.stream(Attribute.values())
.filter(attribute -> attribute.getAttributeName().equalsIgnoreCase(attributeName))
.findFirst()
.orElseThrow(() -> new RuntimeException(String.format("Invalid Attribute name - %s", attributeName)));
//.orElse(null);
}
//Getter, Setter & Args Constructor (Use Lombok to reduce Boiler Plate code)
}
Update Logic
public void updateFriend(int id, String toChange, String newValue) {
Attribute attribute = Attribute.getAttributeSetterByName(toChange);
for (Friend friend : friends) {
if (friend.getId() == id) {
attribute.getAttributeSetter().accept(friend, newValue);
break;
}
}
}
You can use a java.util.function.Consumer<T> object to change an object inside your container where you have all the type safety you get. Instead of having magic strings and string arguments for values, which might not be even for string fields, you can work directly on the objects type:
public void updateFriend(int id, Consumer<Friend> c) {
// find the friend object
Friend found = null;
for (Friend f: this.friends) {
if (f.getId() == id) {
found = f;
break;
}
}
if (found == null) {
throw new IllegalArgumentException("There is no friend object with the given id");
}
// use the friend object.
c.accept(found);
}
You can use this method like this:
container.updateFriend(42, f -> f.setVorName("abc"));
container.updateFriend(9, f -> f.setAddress(some_address_object));
#Entity
public class Person {
private Integer id = null;
private String name = null;
private String price = null;
private Date created = null;
// String Representation:
#Override
public String toString() {
return name;
// I want to return name and price
}
I want to return name and price in toString function ? This is right to return more than one string in toString function. If you make relation in other's Entity ManyToMany ?
Please suggest me if I am doing right or wrong as I want to show these fields in other entity where I make relations.
Thanks!
Usually the toString() method returns a string-representation of the object and not the object's members themself. So if you need a representation of name and price you could do
return "Name: " + name + ", Price: " + price;
If you really want to receive the members name and price you should generate getters for those and use them in the caller.
Another possibility is to "wrap" the two strings in some sort of data class.
This is right to return more than one string in toString function. If you make relation in other's Entity ManyToMany ?
That could be
#Override
public String toString() {
return "Name :" +name + " Price : "+price;
}
If you still have more Objects related to it, just append in the last. So that you won't loose information.
You can do it like this:
return name+" "+price;
You can create another method to return both.
you can return String array as well so that you don't need to split the string if you need to perform any operation on name and price.
You can use a StringBuilder and build up your composed String efficiently from both the name, the price and whatever you want.
Here the documentation.
Anyway, the response is no, you cannot send back two strings, but you can return a string that is a composition of the others.
I have a class which has many fields of the type String. I want to write a method as a setter for all these fields, so I need a switch. Here comes my question, how to map the field name into an integer to be fit in switch? I don't want Integer.parseInt(), because I don't know what char may be and couldn't choose a appropriate radix. I don't want to manually build a map neither. Is there any handy trick?
Why don't you use strings in switch case itself? You don't need to use make any relation between string and integer for that. Java 7 maintains this internally.
switch(string){
case "one":
-- do something--
break;
case "two":
-- do something --
break;
....
..
And if you really want to maintain a nice and effective relation between string and integer so that you can use that in switch - have a look in the implementation of switch using string - and check its byte code.
You can use List which will have setter and getter. List can hold any kind of Object.
List<Employee> empList = new ArrayList(Employee);
public List<Employee> getEmpList() {
return empList;
}
public void setEmpList(List<Employee> empList) {
this.empList = empList;
}
In your Employee Class
Employee
String firstName
String lastName
String address
int age
Why don't you do what everybody else does and encode the field name into the method name instead of a parameter:
public void setXXX(int xxx) // sets XXX
public void setYYY(int yyy) // sets YYY
If you write an enum where the members are named exactly as your input strings:
enum MyEnum { CASE_1, CASE_2 }
Then you can simply switch on MyEnum.valueOf(inputString):
switch (MyEnum.valueOf(inputString)) {
case CASE_1: setCase1Field(); break;
case CASE_2: setCase2Field(); break;
}
I should take from a variable enum its value and transform it to string.how can i do?
here it is the type enum:
public enum State{
b,c,p;
};
now i have to insert into an object String one value.
You might use enum.name orenum.toString to get the name of the enum constant, or enum.ordinal to get the ordinal position.
you can use name() or toString(), so :
State aState = State.c;
String strState = aState.name();
See here the official java reference for more information...
State.b.toString() will return "b". The same goes for the other ones.
Usually,
State state = ...;
String string = state.toString();
should work, but it is not recommended since someone might override toString for some other purpose.
Instead the method you are looking for is
String string = state.name();
As an aside, your enumerated stated should always be all in capitals, and they should have descriptive names. It's not a language rule, but a convention. For example enum State { ON, OFF, PAUSED; }.
I tend to do something more complicated, but I find that it's more flexible:
public enum MyEnumeration {
SOME_NAME("Some Name"),
OTHER_THING("Other Thing"),
...
MORE_VALUES("More Values"),
private final String displayName;
private MyEnumeration(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
This way, I use standard capitalization for my enums in code, but can have a more presentable name for them.
This trick can also be used to replace ordinal, by initializing a number, and then you don't need to worry about rearranging your enums.
Method #1: Using the built-in toString() and name() methods
If you want to print a String that is the same as the value of the State, then you can use the toString() method, or the name() method.
System.out.println(State.b); // Prints "b"
System.out.println(State.c); // Prints "c"
System.out.println(State.p); // Prints "p"
Method #2: Using a constructor to create a custom mapping
If you want to have a custom String associated with each of those states, you can use a constructor to associate a particular value with each enum value:
public enum State{
b("State B"), c("State C"), p("State P");
private String longName;
private State(String longName) {
this.longName = longName;
}
#Override
public String toString() {
return this.longName;
}
};
Of course, if you don't want to break the default toString() usage, you can create a different method called getFullName(), for example, to return the custom value.