Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ensure that a field is properly encapsulated?

I wonder if there's a simple way to to find all methods accessing a field directly. More precisely:

I'd like to assure that there's exactly one method writing a field and exactly one method reading it. All other accesses should use these two.

Background: When a field gets written, I need to record the fact somewhere I can do this easily using a generated setter, but I'd like to assure that I don't circumvent it somewhere.

It's for mobile rather than server, so I don't want / can't use interfaces or run-time bytecode rewriting...

I know, there's ASM, but AFAIK using it means more work that I'd like to spend. I hope, there's a better way.

Update

I didn't think of it, but have to state that code changes are allowed, but memory is tight. So encapsulating fields (e.g., Java FX style) or making a backup is too bad. There are quite a few fields, so actually anything requiring to touch them all is not good.

I could imagine parsing the sources, which is either complicated or prone to false positives as the same identifier has different meanings depending on the context. It may be even shadowed (e.g., in a nested class declaring an equally-named variable), but then I'd gladly change the code to avoid the problem.

Getting a structured information from the class file would surely be better.

like image 951
maaartinus Avatar asked Oct 16 '19 10:10

maaartinus


People also ask

How do you achieve encapsulation?

Encapsulation can be achieved by Declaring all the variables in the class as private and writing public methods in the class to set and get the values of variables. It is more defined with the setter and getter method.

Which of the following is a proper encapsulated class?

We can create a fully encapsulated class in Java by making all the data members of the class private. Now we can use setter and getter methods to set and get the data in it. The Java Bean class is the example of a fully encapsulated class.

What is the purpose of encapsulation?

Encapsulation allows you to hide specific information and control access to the internal state of the object. If you're familiar with any object-oriented programming language, you probably know these methods as getter and setter methods.

How do properties help provide encapsulation?

Properties allow clients to access class state as if they were accessing member fields directly, while actually implementing that access through a class method. This is ideal. The client wants direct access to the state of the object and does not want to work with methods.


2 Answers

Encapsulation in Java is at the object or class level; the strictest access control modifier is private, but even then, every method within the same class can access the private fields. So, if you want to encapsulate behaviour of fields, this can be achieved by representing the fields as objects.

Here's a class representing a mutable field:

public class MyField<T> {
    private T value;

    MyField(T initialValue) {
        value = initialValue;
    }

    public T get() {
        return value;
    }

    public void set(T newValue) {
        // any logging goes here
        value = newValue;
    }
}

Then if you want this logging behaviour to apply to a field name, declare name as type MyField<String> instead of String:

public class Person {
    private final MyField<String> name;
    private final MyField<Integer> age;

    public Person(String name, int age) {
        this.name = new MyField<>(name);
        this.age = new MyField<>(age);
    }

    public String getName() {
        return name.get();
    }

    public int getAge() {
        return age.get();
    }

    public void setName(String name) {
        this.name.set(name);
    }

    public void setAge(int age) {
        this.age.set(age);
    }
}

Advantages:

  • Since MyField.value is private, it's easy to verify across all instances that its value is never set without the logging behaviour being triggered.
  • The Java compiler's static checks are sufficient for checking that the field's value is only accessed via its get and set methods; there is no need for a separate verification stage.
  • You can apply this to just the fields you want the logging behaviour on.

Disadvantages:

  • Each of those MyField objects has some overhead in memory use.
  • The extra method calls to get and set will have some overhead in running time.
  • The extra code to call .get() is not much, but it could harm readability in more complex expressions.
like image 151
kaya3 Avatar answered Oct 10 '22 01:10

kaya3


I could imagine parsing the sources, which is either complicated or prone to false positives as the same identifier has different meanings depending on the context. It may be even shadowed (e.g., in a nested class declaring an equally-named variable), but then I'd gladly change the code to avoid the problem.

That's why modern IDEs exist -- they can analyze your code based on context instead of just grepping sources.

Take IntelliJ IDEA, for example: enter image description here

Usages of field, method class, or other things are one shortcut away: enter image description here Not only in your project, but in dependencies and other linked projects as well!

This is also available in Eclipse-based IDEs and NetBeans, probably others too.

If you don't use any IDE, you can still use linters like Checkstyle. Just mark the field deprecated and ignore warnings in methods where you know usage is permitted, more about ignoring Checkstyle warnings in this answer: https://stackoverflow.com/a/1706844

like image 25
Pavlus Avatar answered Oct 10 '22 01:10

Pavlus