why default method not recognized as property(getter/setter)? - java

Interface:
public interface SomeInt{
Integer getX();
void setX(Integer value);
default Integer getY(){
return getX();
}
default void setY(Integer value){
setX(value);
}
}
A Class implement it:
public class A implements SomeInt{
private Integer x;
public Integer getX(){
return x;
}
public void setX(Integer value){
x = value;
}
}
When initialized, I can call the method getY & setY, and get the right return.
But I cannot use it in JSP(EL), like ${instance_of_class_a.y}. And the property Y is not list in IDEA's variables list(Debug Mode).
If I do add the getY & setY explicitly in class A, everything is ok.
Why? I think default method is like a compiler sugar.
Sorry for my poor english and the mistakes in the code, I've correct it.

The question is a bit ill written here, so maybe something went wrong.
Especially add #Override for typos.
interface SomeInt {
int getX();
void setX(int x);
default int getY() {
return getX();
}
default void setY(int value) {
setX(value);
}
}
static class A implements SomeInt {
private int x;
#Override
public int getX() {
return x;
}
#Override
public void setX(int value) {
x = value;
}
}
System.out.println("Methods:");
for (Method m : A.class.getMethods()) {
System.out.printf("+ %s%n", m.getName());
}
for (Method m : A.class.getDeclaredMethods()) {
System.out.printf("- %s%n", m.getName());
}
In general for getters/setters Class.getMethods is used.
Methods:
+ setX
+ getX
...
+ setY
+ getY
- setX
- getX

I think I've got the answer.
BeanELResover using java.beans.Introspector to getBeanInfo(Properties)
public static BeanInfo getBeanInfo(Class<?> beanClass)
throws IntrospectionException
{
if (!ReflectUtil.isPackageAccessible(beanClass)) {
return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
}
ThreadGroupContext context = ThreadGroupContext.getContext();
BeanInfo beanInfo;
synchronized (declaredMethodCache) {
beanInfo = context.getBeanInfo(beanClass);
}
if (beanInfo == null) {
beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();
synchronized (declaredMethodCache) {
context.putBeanInfo(beanClass, beanInfo);
}
}
return beanInfo;
}
The constructor of Introspector call a method "findExplicitBeanInfo" to getDeclaredMethods of current class. Then do it with its superClass until Object or stopClass. The method of interfaces will not be loaded here.
private Introspector(Class<?> beanClass, Class<?> stopClass, int flags)
throws IntrospectionException {
this.beanClass = beanClass;
// Check stopClass is a superClass of startClass.
if (stopClass != null) {
boolean isSuper = false;
for (Class<?> c = beanClass.getSuperclass(); c != null; c = c.getSuperclass()) {
if (c == stopClass) {
isSuper = true;
}
}
if (!isSuper) {
throw new IntrospectionException(stopClass.getName() + " not superclass of " +
beanClass.getName());
}
}
if (flags == USE_ALL_BEANINFO) {
explicitBeanInfo = findExplicitBeanInfo(beanClass);
}
Class<?> superClass = beanClass.getSuperclass();
if (superClass != stopClass) {
int newFlags = flags;
if (newFlags == IGNORE_IMMEDIATE_BEANINFO) {
newFlags = USE_ALL_BEANINFO;
}
superBeanInfo = getBeanInfo(superClass, stopClass, newFlags);
}
if (explicitBeanInfo != null) {
additionalBeanInfo = explicitBeanInfo.getAdditionalBeanInfo();
}
if (additionalBeanInfo == null) {
additionalBeanInfo = new BeanInfo[0];
}
}

Related

Undefined arguments in return with INT

i have the code like this when i create it like this
public final class PhpArray extends AbstractMap
{
private TreeMap t;
private HashMap m;
public PhpArray() {
this.t = new TreeMap(Request.PHP_ARRAY_KEY_COMPARATOR);
this.m = null;
}
#Override
public Object put(final Object key, final Object value) {
if (this.m != null) {
return this.m.put(key, value);
}
try {
return this.t.put(key, value);
}
catch (ClassCastException e) {
this.m = new HashMap(this.t);
this.t = null;
return this.m.put(key, value);
}
}
#Override
public Set entrySet() {
if (this.t != null) {
return this.t.entrySet();
}
return this.m.entrySet();
}
public int arraySize() {
if (this.t == null) {
throw new IllegalArgumentException("The passed PHP \"array\" is not a sequence but a dictionary");
}
if (this.t.size() == 0) {
return 0;
}
return 1 + this.t.lastKey();
}
}
but when i update my project i got error in the code
return 1 + this.t.lastKey();
the error is an arguments + is undefined.. why like that ? and how to fix the problem ?
TreeMap is a generic class but in the code in your question you have used it without type parameters. This means that this line of your code:
private TreeMap t;
is essentially this:
private TreeMap<Object, Object> t;
In other words t.lastKey() returns an Object and the operator + can't be used with Object because an Object is not a number.
Perhaps you meant to call method size() rather than method lastKey()?
Perhaps this tutorial will help?

Method that always return null

I'm stuck with a piece of a code I'm translating from Java to C#.
Basically, I have a Map(Dictionary) with keys composed by Pair and Values represented by a class made by me (Square); in this class there's only one field, which is Optional (yes, I create the Optional class in C#).
At the beginning I fill this Dictionary with pairs to make a simil-grid and empty Optional, as you can see in the code below.
class World
{
private Dictionary<Pair<int, int>, Square> map =
new Dictionary<Pair<int, int>, Square>();
public World(int width, int height)
{
this.size = new Pair<int, int>(width, height);
for (int w = 0; w < this.size.GetX(); w++)
{
for (int h = 0; h < this.size.GetY(); h++)
this.map.Add(new Pair<int, int>(w, h),
new Square(Optional<Entity>.Empty()));
}
}
}
And this is the Square class
class Square
{
private Optional<Entity> entity;
public Square (Optional<Entity> entity)
{
this.entity = entity;
}
public Optional<Entity> GetEntity()
{
return this.entity;
}
public void SetEntity(Optional<Entity> entity)
{
this.entity = entity;
}
}
Here's the problem, this function below always returns null when I try to get an existent value from the Dictionary, it throws System.NullReferenceException: Object reference not set to an instance of an object.
In this code I cut away all the controls, but I know that I try to get a value already inserted; also, I tried to run Dictionary.ContainsValue and it return false! But I do have inizialed the Dictionary.
public Square? GetSquare(int x, int y)
{
if (y < this.size.GetY() && y >= 0 && < x this.size.GetX() && x >= 0)
{
this.map.TryGetValue(new Pair<int, int>(x, y), out Square? square);
return square;
}
throw new InvalidOperationException("no square in this position!");
}
I leave here the code of the Optional class too, but I'm almost 100% sure that it's not the problem
public class Optional<T>
{
private T value;
public bool IsPresent { get; set; } = false;
private Optional() { }
public static Optional<T> Empty()
{
return new Optional<T>();
}
public static Optional<T> Of(T value)
{
Optional<T> obj = new Optional<T>();
obj.Set(value);
return obj;
}
private void Set(T value)
{
this.value = value;
this.IsPresent = true;
}
public T Get()
{
return value;
}
}
This is Pair class
public class Pair<X, Y>
{
private X first;
private Y second;
public Pair(X first, Y second)
{
this.first = first;
this.second = second;
}
public X GetX()
{
return this.first;
}
public Y GetY()
{
return this.second;
}
public override string ToString()
{
return "<" + first + "," + second + ">";
}
}
Ok, solved it.
The problem was, as you said, the Pair class.
I substitute it with the ValueTuple<> class and now everything works fine, still thanks.

Java Referring to any object

I would like to find an object. There is only one object with the variable x=10.
Is it possible? I hope you get what I try to explain... :)
if (any object of the class X .getValue() == 10)
...
Class X
public int getValue(){
return x;
}
List<X> xList = new ArrayList<>();
public static X findXWithValue(List<X> xList, int value) {
X xWithValue = null;
for(int i = 0 ; i < xList.size()-1 ; i++) {
if (value == xList[i].getValue()) {
xWithValue = xList[i];
break;
}
}
return xWithValue;
}
Br,
Rakesh
Something like:
public class ObjectFinder {
public static boolean checkObject(Object o, String methodName, int value) {
return Stream.of(o.getClass().getDeclaredMethods())
.filter(method -> method.getName().equals(methodName))
.filter(m -> checkType(m, int.class))
.map(m -> {
try {
return (int) m.invoke(o);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return 0;
}
}).anyMatch(v -> value == v);
}
private static boolean checkType(Method method, Class type) {
return method.getReturnType() == type;
}
}
and you can test it in:
public static void main(String[] args) {
System.out.println(checkObject(new X(), "valueOf", 2));
}

Interface and type casting

In the Java 8 tutorial about interface, one example says that when a class implements an interface, one has to type cast the interface type into the class type in order to invoke methods of this class, as shown by the following example from the java 8 tutorial:
public class RectanglePlus
implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
// four constructors
public RectanglePlus() {
origin = new Point(0, 0);
}
public RectanglePlus(Point p) {
origin = p;
}
public RectanglePlus(int w, int h) {
origin = new Point(0, 0);
width = w;
height = h;
}
public RectanglePlus(Point p, int w, int h) {
origin = p;
width = w;
height = h;
}
// a method for moving the rectangle
public void move(int x, int y) {
origin.x = x;
origin.y = y;
}
// a method for computing
// the area of the rectangle
public int getArea() {
return width * height;
}
// a method required to implement
// the Relatable interface
public int isLargerThan(Relatable other) {
RectanglePlus otherRect
= (RectanglePlus)other;
if (this.getArea() < otherRect.getArea())
return -1;
else if (this.getArea() > otherRect.getArea())
return 1;
else
return 0;
}
}
In the method isLargerThan(Relatable other), other is casted to type RectanglePlus in order to invoke getArea().
In the other example about default methods in interface, the compareTo(Card o) method doesn't type cast o to type PlayingCard, but can invoke int hashCode() directly, I don't understand this. Thanks for your help.
package defaultmethods;
public class PlayingCard implements Card {
private Card.Rank rank;
private Card.Suit suit;
public PlayingCard(Card.Rank rank, Card.Suit suit) {
this.rank = rank;
this.suit = suit;
}
public Card.Suit getSuit() {
return suit;
}
public Card.Rank getRank() {
return rank;
}
public boolean equals(Object obj) {
if (obj instanceof Card) {
if (((Card)obj).getRank() == this.rank &&
((Card)obj).getSuit() == this.suit) {
return true;
} else {
return false;
}
} else {
return false;
}
}
public int hashCode() {
return ((suit.value()-1)*13)+rank.value();
}
public int compareTo(Card o) {
return this.hashCode() - o.hashCode();
}
public String toString() {
return this.rank.text() + " of " + this.suit.text();
}
public static void main(String... args) {
new PlayingCard(Rank.ACE, Suit.DIAMONDS);
new PlayingCard(Rank.KING, Suit.SPADES);
}
}
In short: Because hashCode is defined in java.lang.Object and every other class extends Object implicitly.
So when you have
public int compareTo(Card o) {
return this.hashCode() - o.hashCode();
}
the compiler already knows that o is of type Card which extends Object which defines a hashCode method. No need for an explicit cast.
On the other hand in your isLargerThan method the parameter is of type Relatable:
public int isLargerThan(Relatable other) {
RectanglePlus otherRect
= (RectanglePlus)other;
if (this.getArea() < otherRect.getArea())
return -1;
else if (this.getArea() > otherRect.getArea())
return 1;
else
return 0;
}
And judging from the link you provided, the getArea method is defined in RectanglePlus only. Since the compiler only sees Relatable it does not know anything about a getArea method at this point and you need to explicitly cast other to RectanglePlus to be able to access it.
Note that you should actually do an instanceof check before casting to avoid a ClassCastException when other is not a RectanglePlus (you don't know if there might be other classes implementing Relatable).
Let me try a non-code related example:
If people have a pet they usually give it a name. So whatever pet you have, one can always ask for its name (cf. hashCode). But they cannot ask you to make it bark (cf. getArea) unless they know that it is a dog.
And you will probably fail to make a cat bark (cf. ClassCastException).

How to generically populate an object if the field names are provided?

I need to create and populate an object inside a method. The only information is the member field name (passed as a string) and the relevant value for that field (passed as an Object). What is the most appropriate design pattern taking into account performance? - reflection, if comes with a penalty, would not be a preferred approach.
Update:
The value to be set comes from an object that acts as a generator of the values having a set of methods that return the proper value for the specific field. E.g. for member Double x; it would be generator.getX()
A simple function to copy all the getters to all the available setters is as follows. With some more work you can cache this information and speed it up but it is likely to be fast enough as it is.
public static <T> T copyTo(Object from, T to) {
for(Method m : to.getClass().getMethods()) {
if (!m.getName().startsWith("set") || m.getParameterCount() != 1)
continue;
try {
Method getter = from.getClass().getMethod("g" + m.getName().substring(1));
m.invoke(to, getter.invoke(from));
} catch (NoSuchMethodException ignored) {
// ignored
} catch (InvocationTargetException | IllegalAccessException e) {
throw new AssertionError(e);
}
}
return to;
}
Note: Only the fields where there is a matching getter and setter will attempt to copy from one to the other.
public static void main(String[] args) {
One orig = new One(1, "hi", 3);
One to = new One();
One copy = copyTo(orig, to);
System.out.println(to);
}
static class One {
int x;
String y;
double z;
public One() {
}
public One(int x, String y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
public double getZ() {
return z;
}
public void setZ(double z) {
this.z = z;
}
#Override
public String toString() {
return "One{" +
"x=" + x +
", y='" + y + '\'' +
", z=" + z +
'}';
}
}
prints
One{x=1, y='hi', z=3.0}
If you want to create an object generically you need to use reflection.
The only alternative is byte code generation which will be much more complex to implement and only save you a fraction of a micro-second.
How many days is it worth sending to implement this to save a micro-second?
If you know the class name of the object then what you can do is:
public Object populate(String className,String fieldName,Object value) throws Exception{
Class clazz = Class.forName(className);
Object o = null;
for(Field f: clazz.getFields()){
if(f.getName().equals(fieldName)){
o = clazz.getConstructor().newInstance();//default constructor if it exists
f.set(o, value);
break;
}
}
return o;
}
EDIT:
Since you know the class(comment under question) then you can use is the function I wrote just with this change and not className parameter:
Class clazz = Class.forName(YourClass.class.getName());
EDIT2:
If I understand the update you are asking about how to know which method to invoke to get the value.
On your generator class you can get the list of methods it has. Then if your method are named getFieldName() you can once you have the field name find the method with the name getFiledName.
Example:
for(Method m:GeneratorClass.class.getMethods()){
System.out.println(m.getName());
//analyze method name and field name to determine which method to call
//..
boolean callThis = true;//result of analysis
if(callThis){
//Object value = m.invoke(obj);
//obj==generator
}
}

Categories