简体   繁体   中英

Scala extend trait field not found

I have a scala trait with a public UUID that has a default value:

trait pet {
    var uuid_ : UUID = UUID.randomUUID
}

now I am creating multiple classes, also in scala:

class dog extends pet {
    var foo = 1
}
class cat extends pet {
}
class fish extends pet {
}

After that I created a method in Java (old project with both languages mixed).
Here the snipped with my problem. In the variable somePet is an instance of dog , cat or fish . But it is not clear what of them exactly:

// printing all variables in the console for human testing
Serializer.printAllFields(somePet);

// The somePet Variable must be a pet
if(!pet.class.isAssignableFrom(somePet.getClass()))
    throw new Exception("Not a pet.");

// get the UUID of the pet
UUID uuid_;
try {
    Field f = pet.class.getField("uuid_");
    f.setAccessible(true);
    uuid_ = (UUID) f.get(somePet);
}catch(Exception e){
    // no uuid found
    throw e;
}

But when I run the code I get the following error:

Exception in thread "main" java.lang.NoSuchFieldException: uuid_

And the stacktrace points on the line with Field f = pet.class.getField("uuid_"); .
But what is wrong with the code?
An alternative I thought was replacing this exact line with:

Field f = ntObj.getClass().getField("uuid_");

But this also fails.
So where is the variable uuid_ ?
Because when I print out all variables in the console of the current somePet with a Serializer, I get something like

* cat.uuid_ = 34d7a781-472d-4d98-861e-7cff08045445;

or

* dog.foo = 1
* dog.uuid_ = 34d7a781-472d-4d98-861e-7cff08045445;

in the console.
So the variable uuid_ is there with a default value.
(I am using the serializer from this post )

So how do I get the uuid_ variable in my java snippet?

First of all, there is no such Serializer under the the package java.util , so you're using something else.

An trait is translated to a Java interface , which cannot have fields per se.
However you're trying to access the field via the Pet interface

pet.class.getField(...)

That won't work. You need to look for the field inside the concrete class .
Also, the field will be private by default, since the access is granted via a getter .

The getField method is able to retrieve every public field for the entire class hierarchy (which mean even superclasses), while getDeclaredField is able to retrieve protected and private fields, but only on the exact class you're calling it from. You need also a call to setAccessible(true) , because

A value of true indicates that the reflected object should suppress Java language access checking when it is used. A value of false indicates that the reflected object should enforce Java language access checks

The correct code would be ( dog is the concrete instance)

final Field uuid = dog.getClass().getDeclaredField("uuid_");
uuid.setAccessible(true);
final Object o = uuid.get(dog);

Or using the automatic getter

final Method uuid = dog.getClass().getMethod("uuid_");
final Object o = uuid_.invoke(dog);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM