Generic property with AOP-functionality in Java
My first thought is: Interesting.

The Property&lt;T&gt; class as it is right now

First, some feature-requests or changes you can consider:


You could combine beforeSet and onSet into a BiFunction&lt;T, T, T&gt; (which is the same as BinaryOperator&lt;T&gt;).
It could potentially be useful to use the afterSet as a BiConsumer, to also let it know about what the previous value was.
What if a previous function has been set for afterSet/beforeSet/etc.? I think you should do a null-check there and either throw an exception if it has already been set, or auto-add it (using the default methods that exists on the interfaces), such as this.afterSet = this.afterSet.andThen(afterSet);
I'm not a big fan of the onGet feature. In my experience, getters should do what they do best: Get the actual value. Having the possibility to modify the value that should be returned seems risky. Doing conversion like String.toLowerCase() for example should lie where it is being used, or the property should be set to lower case right from the start IMO.
Actually, thinking about it... I'm not sure about any of the get-features... I just don't see a specific real use case for them.


The system itself

I'm going to list a couple of good things and a couple of bad things with this approach:

Good things:


Allows you to manipulate the "behavior" of a property in quite some detail.
Allows you to manipulate the "behavior" of a property in quite some detail.
Allows you to manipulate the "behavior" of a property in quite some detail.


(One time for the beforeSet feature, once for the onSet and once for afterSet. Three-in-one)

Bad things:


Primitive types needs to be wrapped into it's non-primitive type, like int -> Integer. This leads to slower code as there will be some auto-boxing, and it will allow the value null where you might not want that value, or you have to handle the null with a beforeSet or similar. Although you could potentially separate classes for  IntProperty, BooleanProperty, etc. I don't think you'd want to do all those classes.
When should I make my Java classes use this approach or not? Should I introduce them when I feel like I need them or should I play safe and use this approach on all my properties, even though when I will probably never need them? I can imagine there will be some headache going on no matter what option I would choose.
It's breaking the Java beans style, which isn't a bad thing by itself. It can cause a bit of a problem when using libraries that depends a lot on reflection, but there are normally ways to work around that. (I.e. telling the library to ignore the private property and use the getters and setters provided).


A different approach that's capable of doing the same thing

Consider Google's EventBus code. With the right event classes, this can accomplish the same things. Example code following: (not tested, but something similar would work)

public class Foo {

    private int bar;
    private EventBus events = new EventBus();

    public Foo() {
        bar = 42;
        events.registerListener(this);
    }

    @Subscribe
    private void onSetChanged(BarChangeEvent event) {
        System.out.printf("bar will be set from %d to %d.%n", event.getOldValue(), event.getNewValue()));
    }

    public int getBar() {
        return bar.get();
    }

    public void setBar(int bar) {
        events.post(new BarChangeEvent(this.bar, bar));
        this.bar = bar;
    }
}


Of course, there's bad things to say about this approach as well. One example is that it always creates a new object whenever bar is set. For most projects of course, the @Subscribe method is probably not inside the Foo class. Instead the class will have to expose the EventBus somehow (or the EventBus can be injected into the Foo class).

Still another approach

This is the fastest approach, but unfortunately it is the least flexible approach as well.

The simple "do-it-in-the-setter approach"

public class Foo {

    private int bar;

    public Foo() {
        bar = 42;
    }

    public int getBar() {
        return bar;
    }

    public void setBar(int bar) {
        System.out.printf("bar will be set from %d to %d.%n", this.bar, bar);
        this.bar = bar;
    }
}


Summary

You might have use for your Property&lt;T&gt; code, if so then great. I personally would probably not use it. (I tend to use the Event-driven approach when I need to, not for each and every property of course. Sometimes I might even use the "put-it-in-the-setter-approach")


  Does this put too much logic into properties?


Personally, I think it does yes. But that's just my two three cents.