two class:
public class BaseDo<K> {
protected K id;
public K getId() {
return id;
}
public void setId(K id) {
this.id = id;
}
}
public class BeanDo extends BaseDo<Integer> {
private String beanName;
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
}
I want use reflect to implment like this:
BeanDo beanDo = new BeanDo();
beanDo.setId("string here");
Integer type reference String type value.
Generics in Java are not used at runtime, so as far as the java runtime is concerned you're ID field is of type Object and so can be set to any value regardless of the generics. That said, doing so is a bad idea since anything assuming the generic contract will fail.
You can set the field by reflection as follows:
BeanDo beanDo = new BeanDo();
Method method = BeanDo.getClass().getMethod("setId", Object.class);
method.invoke(beanDo, "SomeRandomString");
That said, doing this is an extreamly bad idea because any code compile against BeanDo will assume that the id is an integer not a String. So any code like beanDo.getId() will fail with a class cast exception because it's not actually an integer.
Like the other posters, I'm somewhat in the dark about what you're trying to achieve.
Something like this?
public class BaseDo<K> {
protected K id;
public K getId() {
return id;
}
public void setId(K id) {
this.id = id;
}
}
public class BeanDo extends BaseDo<Integer> {
private String beanName;
public void setId(String id) {
setId(Integer.parseInt(id));
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
}
Now you can use something like this:
BeanDo beanDo = new BeanDo();
beanDo.setId("2");
What about this:
BeanDo beando = new BeanDo();
beando.setId("string there".hashCode());
I don't quite get what you mean with "I want to use reflect to implement this" though.
I guess you want something like this:
BeanDo doer = ... // get it from somewhere
String id = ... // get it from somewhere else too.
// and you want to set id to the doer bean.
reflectionMagicSetId( doer, id );
And have the method like:
private void reflectionMagicSetId( BandDo doer, String id ) {
/// do some magic here?
}
If that's what you want, what I give you works perfectly.
private void reflectionMagicSetId( BandDo doer, String id ) {
doer.setId( id == null ? 0 : id.hashCode() );
}
If you wann use integer then parse the string to integer as it will contain the integer and use that integer in the calling function argument
It seems like a subclass about the only way to be able to set a string, but still guarantee that anyone who's already calling getId() gets the Integer they expect. Something like this:
public class StringBeanDo extends BeanDo {
private String stringId;
public String getStringId()
{
return stringId;
}
public void setId( Integer val )
{
super.setId( val );
stringId = Integer.toString( val );
}
public void setId( String str )
{
stringId = str;
super.setId( convertStringToInteger( str )); // Do this however you like.
}
}
The implementation of convertStringToInteger would be up to you (it'll depend on what this ID is being used for). The key here is that you're maintaining TWO IDs, and keeping them in sync, so that older code can still limp along to some extent.
Related
Say I have an enum of Things with names:
public enum Thing {
THINGA, THINGB, THINGC, THINGD,
THINGE("Thing E"),
;
public final String name;
private Thing(String pname) {
name = pname;
//...
}
private Thing() {
// See question
}
}
Say I want to do the same thing I did with THINGE for all my other Things, except I want the default name to be the same as that of the enum constant itself, e.g.:
private Thing() {
this(/* the name of the constant itself */);
}
Essentially, I want the implied value of pname to be "THINGA" for THINGA, "THINGB" for THINGB, "THINGC" for THINGC, "THINGD" for THINGD, etc. Using either toString() or name(), the compiler yells:
error: cannot reference this before supertype constructor has been called
Is there any way to avoid this?
Specifically, I include the names for the sake of the user. It feels more natural to look at "Thing E" rather than "THINGE", but its much easier for me to program if I can write a method to turn "THINGA" into "Thing A" and use that in the constructor.
You don't need to give a parameter to the constructor for this, using name() and a bit of String manipulation should get you there.
public static void main(String[] args) {
for (Thing value : Thing.values()) {
System.out.println("value.name = " + value.name);
}
}
public enum Thing {
THINGA,
THINGB,
THINGC,
THINGD,
THINGE;
public final String name;
Thing() {
this.name = name().replace("THING", "Thing ");
}
}
Prints
value.name = Thing A
value.name = Thing B
value.name = Thing C
value.name = Thing D
value.name = Thing E
I believe from your question that you don't want to change what .name() returns, but introduce another field on your enum values which defaults to .name().
You can do this:
public class Comparison
{
public enum Foo {
A, B, C("My C");
private final String myName;
Foo(String myName) {
this.myName = myName;
}
Foo() {
myName = this.name();
}
public String getMyName() {
return myName;
}
}
public static void main(String[] args)
{
System.out.println(Arrays.stream(Foo.values()).map(e -> e.getMyName()).collect(Collectors.joining("\n")));
}
}
Why does Integer field couldn't get the value that i sent. If i use Integer parameter by itself (like sending an ID) in WebMethod works fine.
Also the String field can get the value that i sent without any problem.
Here is the web service:
#WebService(serviceName = "testWS")
public class testWS {
#WebMethod(operationName = "Hello")
public Integer Hello(#WebParam(name = "testData") TEST testData) {
return testData.getINTPROP();
}
}
TEST type definition:
#XmlAccessorType(XmlAccessType.FIELD)
public class TEST {
private Integer INTPROP;//making public also didn't work
public Integer getINTPROP() {
return INTPROP;
}
public void setINTPROP(Integer INTPROP) {
this.INTPROP = INTPROP;
}
private String STRINGPROP;
public String getSTRINGPROP() {
return STRINGPROP;
}
public void setSTRINGPROP(String STRINGPROP) {
this.STRINGPROP = STRINGPROP;
}
}
C# consumer application:
...
test f = new test();
f.INTPROP = 123;
f.STRINGPROP = "abcdef";
var ff = ws.Hello(f);//returns 0
I hope i could explained my problem. thanks.
Try to change the setter to String.
public void setINTPROP(String INTPROP) {
this.INTPROPString = INTPROP;
Then change the String to an integrer with another function.
Return it as an integer, this should solve the problem.
Here is another aproach:
Add this function. Java should be able to handle this.
If the Variable you are passing is a integer, then the function you have will be used. If it is a String, Then this function will be called:
public String setINTPROP(String INTPROP) {
this.INTPROP = Integer.valueOf(INTPROP);
Ok. Marking field with #XmlSchemaType solved my problem.
#XmlSchemaType(name = "string")
public Integer INTPROP
CLARIFICATION:
I do not know the objects name. That is where the problem comes in. I am creating an object like such:
`new Object(String attributes);
I am trying to run code in another class such as:
***.getStuff();
the trick to it is, there is no name for the Object. but i do know what String attributes is
The question: Is there any way to accomplish this without using the dreaded for loop?
This question is a bit tricky to word, but I will try my best. What I want to is get an object that matches a particular field without making a messy for loop. Something along the lines of:
Object A has the field String name.
String nameObj = "Tickle";
Object A has the name "Tickle"
if(nameObj.equals(Object A)){
//bla bla
}
Very confusing wording, yes. Sorry about that. I want to use Object A in my code without having to figure out which object it is, assuming all I have is its name. I am looking for a shortcut around using a for loop, I suppose.
Feel free to ask questions about what I am looking for. Sorry about the terribly worded question.
Poor coding, but this is what I am looking for...
nameObj.getName().getObjectA();
If you have a bunch of objects with names, and you want to grab an object by its name, I suggest you look up the class HashMap. HashMap lets you put in objects under keys, and when you give the hash map a key it returns the object associated with that key. So in your example, the keys would be string names.
Take at this implementation, that demonstrates what #Patashu said, create a map to the objects, in this case I just add an abstract class at the top of all.
import java.util.HashMap;
public class FindMeBaby {
public static void main(String[] args) {
Factory.add(new NiceGuy("first one"));
Factory.add(new FirstChild("ok im late"));
System.out.println(Factory.get("first one")
.getVeryImportantInformationThatOnlyThisClassKnows());
}
}
abstract class ParentOfAll {
protected String id;
public ParentOfAll(String id) {
this.id = id;
}
public String getId(){
return id;
}
public abstract String getVeryImportantInformationThatOnlyThisClassKnows();
}
class FirstChild extends ParentOfAll {
public FirstChild(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "this is a secret";
}
}
class NiceGuy extends ParentOfAll {
public NiceGuy(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "to say the true, i'm not that nice :)";
}
}
class Factory {
private static HashMap allTheObjects = new HashMap();
public static Object add(ParentOfAll object) {
allTheObjects.put(object.getId(), object);
return object;
}
public static ParentOfAll get(String key) {
return (ParentOfAll) allTheObjects.get(key);
}
}
This is another version, of the same implementation with a more transparent aproach, without the Factory class, the Parent itself will keep track of the instances and save in a list.
import java.util.HashMap;
public class FindMeBaby {
public static void main(String[] args) {
NiceGuy foo = new NiceGuy("first one");
FirstChild bar = new FirstChild("ok im late");
System.out.println(ParentOfAll.get("first one")
.getVeryImportantInformationThatOnlyThisClassKnows());
}
}
abstract class ParentOfAll {
protected String id;
public ParentOfAll(String id) {
this.id = id;
add(this);
}
public String getId() {
return id;
}
public abstract String getVeryImportantInformationThatOnlyThisClassKnows();
private static HashMap allTheObjects = new HashMap();
private static Object add(ParentOfAll object) {
allTheObjects.put(object.getId(), object);
return object;
}
public static ParentOfAll get(String key) {
return (ParentOfAll) allTheObjects.get(key);
}
}
class FirstChild extends ParentOfAll {
public FirstChild(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "this is a secret";
}
}
class NiceGuy extends ParentOfAll {
public NiceGuy(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "to say the true, i'm not that nice :)";
}
}
This would mean that the class was initialized, but the variables were not set.
A sample Class:
public class User {
String id = null;
String name = null;
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;
}
}
The actual class is huge that I prefer not to check if(xyz == null) for each of the variables.
Another non-reflective solution for Java 8, in the line of paxdiabo's answer but without using a series of if's, would be to stream all fields and check for nullness:
return Stream.of(id, name)
.allMatch(Objects::isNull);
This remains quite easy to maintain while avoiding the reflection hammer.
Try something like this:
public boolean checkNull() throws IllegalAccessException {
for (Field f : getClass().getDeclaredFields())
if (f.get(this) != null)
return false;
return true;
}
Although it would probably be better to check each variable if at all feasible.
This can be done fairly easily using a Lombok generated equals and a static EMPTY object:
import lombok.Data;
public class EmptyCheck {
public static void main(String[] args) {
User user1 = new User();
User user2 = new User();
user2.setName("name");
System.out.println(user1.isEmpty()); // prints true
System.out.println(user2.isEmpty()); // prints false
}
#Data
public static class User {
private static final User EMPTY = new User();
private String id;
private String name;
private int age;
public boolean isEmpty() {
return this.equals(EMPTY);
}
}
}
Prerequisites:
Default constructor should not be implemented with custom behavior as that is used to create the EMPTY object
All fields of the class should have an implemented equals (built-in Java types are usually not a problem, in case of custom types you can use Lombok)
Advantages:
No reflection involved
As new fields added to the class, this does not require any maintenance as due to Lombok they will be automatically checked in the equals implementation
Unlike some other answers this works not just for null checks but also for primitive types which have a non-null default value (e.g. if field is int it checks for 0, in case of boolean for false, etc.)
If you want this for unit testing I just use the hasNoNullFieldsOrProperties() method from assertj
assertThat(myObj).hasNoNullFieldsOrProperties();
How about streams?
public boolean checkFieldsIsNull(Object instance, List<String> fieldNames) {
return fieldNames.stream().allMatch(field -> {
try {
return Objects.isNull(instance.getClass().getDeclaredField(field).get(instance));
} catch (IllegalAccessException | NoSuchFieldException e) {
return true;//You can throw RuntimeException if need.
}
});
}
"Best" is such a subjective term :-)
I would just use the method of checking each individual variable. If your class already has a lot of these, the increase in size is not going to be that much if you do something like:
public Boolean anyUnset() {
if ( id == null) return true;
if (name == null) return true;
return false;
}
Provided you keep everything in the same order, code changes (and automated checking with a script if you're paranoid) will be relatively painless.
Alternatively (assuming they're all strings), you could basically put these values into a map of some sort (eg, HashMap) and just keep a list of the key names for that list. That way, you could iterate through the list of keys, checking that the values are set correctly.
I think this is a solution that solves your problem easily: (return true if any of the parameters is not null)
public boolean isUserEmpty(){
boolean isEmpty;
isEmpty = isEmpty = Stream.of(id,
name)
.anyMatch(userParameter -> userParameter != null);
return isEmpty;}
Another solution to the same task is:(you can change it to if(isEmpty==0) checks if all the parameters are null.
public boolean isUserEmpty(){
long isEmpty;
isEmpty = Stream.of(id,
name)
.filter(userParameter -> userParameter != null).count();
return isEmpty > 0
}
The best way in my opinion is Reflection as others have recommended. Here's a sample that evaluates each local field for null. If it finds one that is not null, method will return false.
public class User {
String id = null;
String name = null;
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 boolean isNull() {
Field fields[] = this.getClass().getDeclaredFields();
for (Field f : fields) {
try {
Object value = f.get(this);
if (value != null) {
return false;
}
}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return true;
}
public static void main(String args[]) {
System.out.println(new User().isNull());
}
}
Field[] field = model.getClass().getDeclaredFields();
for(int j=0 ; j<field.length ; j++){
String name = field[j].getName();
name = name.substring(0,1).toUpperCase()+name.substring(1);
String type = field[j].getGenericType().toString();
if(type.equals("class java.lang.String")){
Method m = model.getClass().getMethod("get"+name);
String value = (String) m.invoke(model);
if(value == null){
... something to do...
}
}
Best for me is
Stream.of(getClass().getDeclaredMethods()).allMatch(Objects::isNull);
It can be used in a custom annotation + annotation processor to automagically define a boolean isNull() method on the annotated classes.
Based on Irkwz's answer, but a different approach:
public class SomeClass{
private String field1;
private String field2;
private ComplexField field3;
private String field4;
private Integer field15;
public boolean isNullAllFields() {
return Stream.of(this.getClass().getDeclaredFields()).anyMatch(element -> (element != null));
}
}
And the end of the day u invoke isNullAllFields method to figure out wheter the object fields are empty.
If you want to do the opposite i.e check if some/all members of class are non-non, the check this answer.
In order to make sure that certain members of the class are always non-null, we can use lombok #NonNull annotation on the individual fields of the class.
import lombok.Data;
import lombok.NonNull;
#Data
public class DataClass {
#NonNull
private String data1;
private int data2;
#NonNull
private String data3;
#NonNull
private String data4;
#NonNull
private String data5;
private String data6;
DataClass(String data1,...) {
// constructor
}
}
Easiest way is to convert the class to a map and get its keys and with stream check if any or all key's values are null or not, you can take input from user as well whether they want to check for specific set of keys only!
Below is the code to check whether any of the key's value has null, you can change stream config to all match or any match as per your requirement
Just replace isNullOrEmpty method i have used with proper null or empty check condition for that particular collection
public boolean checkIfAnyFieldIsNull(Object instance, Set<String> fields){
try {
Map<String, Object> instanceMap = new Gson().fromJson(new GsonBuilder().serializeNulls().create().toJson(instance), Map.class);
if(!isNullorEmpty(instanceMap)) {
fields = isNullorEmpty(fields) ? instanceMap.keySet() : fields;
return fields.stream().anyMatch(curField -> isNull(instanceMap.get(curField)));
}else{
return false;
}
}catch (Exception e){
return false;
}
}
}
Try this method once, its works for me!!
private fun checkIfAnyDataIsNull(model: YourModelCass): Boolean {
return Stream.of<Any>(
model.date,
model.merchantName,
model.payment,
).allMatch(Objects::isNull)
}
You can use the simple solution:
if(user.equals(new User()){
//your processing goes here
}
If I have a Object
public class Genre {
private int id;
private int name;
}
And the id and name were been determined in advance, for example
if (id == 1)
name = "action";
else if (id == 2)
name = "horror";
My problem is how to create these two methods well
Genre.getName(1); // return "action";
Genre.getId("action"); // return 1;
I thought maybe I can use enum, like
public enum Genre {
ACTION(1), HORROR(2);
private final int id;
private final String name;
private Genre(int id) {
this.id = id;
this.name = getName(id);
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public static String getName(int i) {
switch(i) {
case 1 : return "action";
case 2: return "horror";
default :
return null;
}
}
}
But in this way, I have no idea how to
Genre.getId("action"); // return 1;
And im afraid i use enum not correctly.
Could you give me some advice? Thanks!
---
At first, What I want to do this is in my case i want to use id or name to find the name or id like
int id = 1;
Genre.getName(id); // return "action"
or
String name = "action";
Genre.getId(name); // return 1
And now thanks for all the advices, I realize why I want to do is
int id = 1;
Genre.getGenre(id); // return Genre that id = 1 and the name = "action"
or
String name = "action";
Genre.getGenre(name); // return Genre that id = 1 and the name = "action"
If you insist on using an enum for this, you can just use the existing enum facilities. The solution below assumes the enum name and ordinal may be used in place of your name and id fields:
public enum Genre {
// ordinal 0, name = "ACTION"
ACTION,
// ordinal 1, name = "HORROR"
HORROR;
}
public static void main(String[] args) {
int horrorOrdinal = 1;
Genre horrorGenre = Genre.values()[horrorOrdinal];
String horrorName = horrorGenre.name();
String actionName = "ACTION";
Genre actionGenre = Genre.valueOf(actionName);
int actionOrdinal = actionGenre.ordinal();
System.out.println(String.format("%s=%s %s=%s", horrorName, horrorOrdinal, actionName, actionOrdinal));
}
Output:
HORROR=1 ACTION=0
Another suitable way would be to use a map for the lookup, like Michał Šrajer suggested:
private static Map<Integer, String> genres = new HashMap<Integer, String>();
public static void main(String[] args) {
initGenres();
int horrorOrdinal = 2;
String horrorName = genres.get(horrorOrdinal);
String actionName = "action";
int actionOrdinal = getGenreIdByName(actionName);
System.out.println(String.format("%s=%s %s=%s", horrorName, horrorOrdinal, actionName, actionOrdinal));
}
private static void initGenres() {
genres.put(1, "action");
genres.put(2, "horror");
}
private static int getGenreIdByName(String genreName) {
for (Entry<Integer, String> entry : genres.entrySet()) {
if (entry.getValue().equals(genreName)) {
return entry.getKey();
}
}
throw new IllegalArgumentException("Genre not found: " + genreName);
}
Output:
horror=2 action=1
Design considerations:
In this example I chose to use the (fast) map lookup for id->name and wrote a seperate method (getGenreIdByName) to do the reverse lookup name->id. You could reverse that, or use a second map to make both lookups fast (at the cost of needing to maintain an extra map).
I chose to store the id and name in the map. You could also use the Genre class itself as the map value. This would allow you to easily add extra fields (like 'description') later on.
If you need to represent you genres in different languages, you can use ResourceBundles to localize the output. Create a language file in your classpath root.
In file genres_nl.properties:
horror=heel eng
action=actie
Where the _nl suffix in the filename indicates the language.
Then in your code, in initGenres:
ResourceBundle genreNames = ResourceBundle.getBundle("genres", new Locale("nl");
And when getting the genre name:
String horrorName = genreNames.getString(genres.get(horrorOrdinal));
Note that getString can throw the runtime exception MissingResourceException if the bundle is not found. To avoid this, make sure you create a 'default' bundle with no suffix (so in this case a file named 'genres.properties') which is automatically used in case no bundle for the used Locale can be found.
Try the valueOf(...) method:
void String getId(String name) {
//names are upper case, so account for that
//handling non-existent names is an excersize for you
valueOf(name.toUpperCase()).getId();
}
Note that there are better methods (like Thilo suggested), but if you have a string only, you might use that.
Edit: another note:
In your getName(int i) method, you might want to return ACTION.name() etc. in order to be more refactoring safe and use the correct case.
You can get its ID by calling Genre.ACTION.getId();
This should do it:
Genre.ACTION.getId()
And if you need to do it at run-time:
Genre.valueOf("ACTION").getId()
ACTION(1, "action"), HORROR(2, "horror");
is a easy way to do it.
But if you are require to do it more often i would suggest you to create your own class and use MAP<-"-,-"-> as micheal said.
Edit:----
As you said the rarely gonna change use this way-->
public enum Genre {
ACTION(0, "action"), HORROR(1, "horror"), ROMANCE(2, "romance"), COMEDY(5, "comedy");
public final int id;
public final String name;
private Genre(int id, String name) {
this.id = id;
this.name = name;
};
public final static int length = Genre.values().length;
public static String[] getGenre() {
String[] genreList = new String[length];
int i = 0;
for (Genre attribute : Genre.values()) {
genreList[i++] = attribute.toString();
}
return genreList;
}
#Override
public String toString() {
return this.name;
}
}
Please remember use this as Genre.HORROR.id
also note that using this way is best as per your requirement.
Why don't you use the Enum Constructor with id and String:
public enum Genre {
ACTION(1, "action"), HORROR(2, "horror");
}
public enum Genre {
ACTION(1, "action"), HORROR(2, "horror");
private final int id;
private final String name;
private Genre(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
If you need to access particular element by it's name, you need to do it this way:
Genre.valueOf("ACTION").getId()
However, if you need to do it often, and in more dynamic way, I suggest to create regular class, and to keep all data in some Map<String, Movie> container.