• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

reflection of private field in super class

 
Maurice Le Chat
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Situation:
The private field id (primary key of DB) ist set by the JEE container and JPA. For this reason no public setter for id shall exist.
To set the id for JUnit tests, reflection is used. To make it a little bit more complicated a class employee inherits from the super class Person. The id field exist in the Person class only.
The following code snippet from JUnit test class works:

Employee empl = new Employee();
try {
// access private field id and set a unique id otherwise set by DB through container
Person pers = new Person(); //ugly workaround, but it works, create dummy super class!
// inherited declared fields are not accessible but:
Field id = pers.getClass().getDeclaredField("id"); // get id ref from super class Person
id.setAccessible(true);
id.setLong(empl, Long.valueOf(i + 1)); // use id ref on employee!
id.setAccessible(false);
} catch (Exception e) {
//handle it
}

Questions:
1.) Though it works, it looks so weird to me, I suspect rather a bug than a feature!
2.) How to do it the clean way?
3.) Who can tell me more about this.

Any background information is welcome.

Cheers Maurice
 
Henry Wong
author
Marshal
Pie
Posts: 21190
80
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Maurice Le Chat wrote:
1.) Though it works, it looks so weird to me, I suspect rather a bug than a feature!


Not sure what you mean by "bug". Tools sometimes need to access private data components of instances, and reflection provides a way to do it.


Unless, you mean "bug" as in a security bug, in that you can access the private component that you should not be allowed to. Basically, the set accessible method goes through the security manager, if you are using a security manager that disallows it (such as loading from an applet), it will throw an exception.

Henry
 
Matthew Brown
Bartender
Posts: 4567
8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You don't need an instance of a class to get the Class object - you can use a class literal. You can delete the line creating a Person, and replace pers.getClass() with Person.class.
 
Jesper de Jong
Java Cowboy
Saloon Keeper
Posts: 15354
39
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Maurice Le Chat wrote:
Questions:
1.) Though it works, it looks so weird to me, I suspect rather a bug than a feature!
2.) How to do it the clean way?
3.) Who can tell me more about this.

You can access private members through reflection. Access specifiers such as protected and private are not meant as security measures, to make data invisible under all circumstances.

There is really no clean way to access private members from outside the class. The whole purpose of private members is to make them not accessible from outside the class. If you want to be able to change the value of a member variable cleanly, provide a setter method (which can be public) to set the value.

Accessing private member variables through reflection is a trick that some frameworks such as Hibernate use. You shouldn't normally do such things in your code yourself.
 
Maurice Le Chat
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
@Matthiew
You are right of course! I didn't yet think about optimizing. I was surprised by the fact to get a handle (field object) to the private id field I want, simply going through the superclass and being able to use this reference to access the id field in a real object, being an extention of this superclass!

@Jesper @Henry
The above is the point! Please read carefully my description of the situation. The application use JPA. A couple of years ago I would have used Hibernate. Anway it's the same. I know reflection and it's use by tools. The point is:
Java SE API says clearly for getDeclaredFields() " ... This includes public, protected, default (package) access, and private fields, but excludes inherited fields." In fact calling getDeclaredField("id") on th derived class Employee throws NoSuchFieldException! So far no surprise. I wonder the fact it's so easy to circumvent this limitation by getting a field object of the superclass and later manipulating with this same object a previously created object of a derived class!
Though I use the reflection in JUnit only, I would be assured to know if this behaviour is by specification, or by accident! If the latter is true, I would like to know, how others do it, or how the tools (Hibernate, etc.) do it.

Thanks

Maurice
 
Rob Spoor
Sheriff
Pie
Posts: 20546
56
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Maurice Le Chat wrote:I wonder the fact it's so easy to circumvent this limitation by getting a field object of the superclass and later manipulating with this same object a previously created object of a derived class!

Well, have you tried? You may be surprised!
 
Maurice Le Chat
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Of course I tried! I havent seen any surprise! The main intend of this thread is to avoid future surprises by getting deeper knowledge from the community. Please explain what do you mean by surprise!
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic