How Functions can be called from java enum? - java

I'm trying to understand how the static method calls from a Java enum works.
To see the full code of this "Working example"
I have the following scenario working, I don't know why
public enum Condition {
GREATER_THAN(PredicateBuilder::generateGreaterThan, ">"),
more values...
private Condition(BiFunction<PredicateBuilder, PredicateContent<?>, Predicate> predicate, String operator) {
this.operator = operator;
this.predicate = predicate;
}
This is the predicate builder, it's an interface implemented by a #Component from Spring:
#Component
public class PredicateLogicalBuilder<V extends Comparable> implements PredicateBuilder<V> {
#Override
public Predicate generateGreaterThan(PredicateContent<V> predicateContent) {
return predicateConversion(predicateContent,Condition.GREATER_THAN);
}
}
The static reference in above Condition enum doesn't complain about:
Non-static method cannot be referenced from a static context
and I don't why because now I'm trying to do something similar and it fails because the static reference of a method isn't static. In the code above is not static either.
Code I'm trying:
public interface MethodCalls<T> {
void randomMethod(T content);
}
#Component
public class TestEnumMethoCalls implements MethodCalls<SomeBean> {
#Override
public void randomMethod(SomeBean content){
System.out.println("Works!!!!");
}
}
public enum NotificationType {
ENUM_TEST_1(MethodCalls::randomMethod);
public final Function<SomeBean,Void> method;
private NotificationType(Function<SomeBean,Void> method){
this.method=method;
}
}
public class TestClass{
public void testMethtod(){
NotificationType.ENUM_TEST_1.method.apply(new SomeBean())
}
}
This piece of code fails saying the Non-static method cannot be referenced from a static context:
ENUM_TEST_1(MethodCalls::randomMethod);
I would like to have 2 answers:
Why the code of the "Working example" works.
If it's mandatory for my current test to use the instance of the MethodCalls how can be injected with DI to the enum (is a static context so I understand it might be tricky if not impossible).

Thanks for the help, now I understood why my "working example" works and how to "Fix" my current issue:
To fix it I have to pass an instance of the implementation of the interface as it's pointed out that enums can only access static methods or an instance of the object to access the method that way.
Final Code
public enum NotificationType {
ENUM_TEST_1(MethodCalls::randomMethod);
public final BiFunction<MethodCalls,SomeBean,Void> method;
private NotificationType(BiFunction<MethodCalls,SomeBean,Void> method){
this.method=method;
}
}
So when I call the apply it looks like this:
public class TestClass{
#Autowired MethodCalls methodCalls;
public void testMethtod(){
NotificationType.ENUM_TEST_1.method.apply(methodCalls,new SomeBean())
}
}
I someone finds out a cleaner way to do this, I would apreciate it.

Related

Try to understand the usage of functions in a Java enum

Here it's my question, why enums require a static/interface access to methods of a referenced class to work?
Here my code example with an interface, it works I guess because it's an Interface so is not a direct reference to an object implementation:
public interface PredicateBuilder<T extends Comparable> {
Predicate generateGreaterThan(PredicateContent<T> predicateContent);
...
}
Then I can use it in the Enum like this:
public enum Condition {
GREATER_THAN(PredicateBuilder::generateGreaterThan, ">"),
...
public final String operator;
public final BiFunction<PredicateBuilder, PredicateContent<?>, Predicate> predicate;
private Condition(BiFunction<PredicateBuilder, PredicateContent<?>, Predicate> predicate, String operator) {
this.operator = operator;
this.predicate = predicate;
}
}
In that scenario works perfect.
Then I tried the following:
#Component
public class SomeClass {
public String someMethod(String param){
return "Stuff";
}
/* This works
* public static String someMethod(String param){
* return "Stuff";
* }
*/
public void applyStuff(TestEnum enum,String param){
enum.action.apply(param)
}
public enum TestEnum{
OPTION_1(SomeClass::someMethod);
private Function<String,String> action;
private TestEnum(Function<String,String> action){
this.action = action;
}
}
}
At this point the IDE complains because requires an static access to the method, I changed to static methods and it works. So why this limitation? Its because Enums are static so they only can access static/reference methods?
So why this limitation? Its because Enums are static so they only can
access static/reference methods?
No, it is because you are calling a method without instantiating an instance of the Class SomeClass. Which leads to the problem that
Non-static method cannot be referenced from a static context
For instance, the following would work:
public class SomeClass {
public String someMethod(String param){
return "Stuff";
}
}
public enum TestEnum{
OPTION_1(a -> new SomeClass().someMethod("something"));
private Function<String,String> action;
private TestEnum(Function<String,String> action){
this.action = action;
}
}
}
because we initiate an object of the Class SomeClass (i.e., new SomeClass()), and therefore we can use a non-static method.
If you add SomeClass::someMethod you are explicitly telling the compiler that you want the static method named someMethod from the class SomeClass.

Java static class that extends an abstract class

This might be a really stupid question, but this is the pattern that I'm interested in implementing.
Here's a basic version of the abstract class that I've implemented.
public abstract class MyCollection {
public abstract String baseUrl();
public void get(ResponseHandler handler) {
myApi.get(baseUrl(), handler);
}
}
And here's my basic static collection object
public class Users extends MyCollection {
#Override
String baseUrl() {
return "/users";
}
}
And here's what I would love to be able to do in one of my controllers
Users.get(new ResponseHandler() {
#Override
public void onSuccess(Object obj) {
//store data
}
#Override
public void onError(Object obj) {
//tell user
}
});
My problem is that Java isn't letting me access the get function inside MyCollection abstract class. Is there a way to get this pattern to work? It seems so pretty and clean to me.
You cannot invoke Users.get() because of the following reasons:
-- static methods are not inherited, even if your MyCollection class would contain a static get() method (which it doesn't contain; it contains an instance get() method, instead)
-- there is no static get() method in your Users class.
These two combined should give you a better view on why you cannot make that call.

Get past static field of jUnit:s #BeforeClass

Is there any way around the classic problem of
public class SomeClass implements SomeOtherInterface {
private static SomeInterface some;
public SomeClass(SomeInterface someInterface) {
some = someInterface;
}
#BeforeClass
public static void doSomethingWithInterface() {
System.out.println(someInterface.someValue()); // prints null
}
}
other than exchanging
System.out.println(someInterface.someValue()); // prints null
with
System.out.println(SomeInterface.someValue());
if someValue is static. The problem is that this is for an framework (extension), and and an implementation of SomeInterface is to be provided by the user.
You set the value of the static member just in the constructor. So before not having at least one object of that class, you won't be able to access someValue(). In Junit the #Before annotation might be useful which is executed before each test and is not static.

How to change a variable from a method

This question is a common issue, and I have tried to look at some thread as Is Java "pass-by-reference" or "pass-by-value"? or How to change an attribute of a public variable from outside the class
but in my case I need to modify a boolean variable, with a Singleton instance.
So far I have a class, and a method which changes the boolean paramter of the class. But I would like to separate this mehod in a manager. The scheme is something like:
public class Test{
private boolean b;
public String getb(){}
public void setb(){}
String test = ClassSingleton.getInstance().doSomething();
}
public class ClassSingleton{
public String doSomething(){
//here I need to change the value of 'b'
//but it can be called from anyclass so I cant use the set method.
}
}
Thanks,
David.
If I understand your requirement - this can solve your problem:
public interface IUpdatable
{
public void setB(boolean newValue);
}
public class Test implements IUpdatable
{
private boolean b;
public String getb(){}
public void setB(boolean newValue) {this.b = newValue;}
}
public class ClassSingleton
{
public String doSomething(IUpdatable updatable)
{
updatable.setB(true);
...
}
}
This way the Singleton does not need to know your Test class - it just knows the interface IUpdatable that supports setting the value of B. Each class that needs to set its B field can implement the interface and the Singleton can update it and remain oblivious to its implementation.
You could extract public void setb(){} into an interface (let's call it BSettable), make Test implement BSettable, and pass an argument of type BSettable into doSomething.
Alternatively, you could make b into an AtomicBoolean and make doSomething accept (a reference to) an AtomicBoolean.
Define b as static variable.
Then call Test.b = value
Perhaps:
public class Test {
private static boolean b;
public static String getB() {}
public static void setB() {}
}
should help? Static fields and methods can be called without an instance (i.e. Test.setB();).
I think your question is not very clear and your sample code is really badly done. Do you actually mean something like this?
public class Test{
private boolean b;
public boolean getb(){return b;}
public void setb(boolean b){this.b = b;}
String test = ClassSingleton.getInstance().doSomething(this);
}
public class ClassSingleton{
private static ClassSingleton __t__ = new ClassSingleton();
private ClassSingleton() {}
public String doSomething(Test t){
t.setb(true);
return null;
}
public static ClassSingleton getInstance(){
return __t__;
}
}
Do you mean your manager is a singleton? or your test class should be singleton? Please be more specific

What to do with static method overrides?

For example,
public class A {
public static int f() { return 1; }
}
public class B extends A {
public static long f() { return 100L; }
}
Unfortunately B.f() couldn't be compiled because B.f() tries to override A.f(), and so the name clashes because the return types aren't compatible.
I'm weired what's purpose to override a static method? Any use case? Can I just hide away A.f() in class B?
Actual usage:
class EntityDTO {
public static List<EntityDTO> marshal(Collection<? extends Entity> entities) {
...
}
}
class BookDTO extends EntityDTO {
public static List<BookDTO> marshal(Collection<? extends Book> books) {
...
}
}
Strictly speaking, static methods can not be overridden. Method overriding is exclusively a feature of object polymorphism, and static methods doesn't belong to any object but the class itself.
Having clarified that, you should not make any of your methods static. That would solve your problem in hand, at least. As the method arguments are different, it will not be considered as overriding, but overloading.
static methods are not overriden...But it is called method hiding. The benefits of using the same method name and parameters are just like any other method overriding benefits
static method can not be overridden.
Notice: your B.f() should return int rather than long to pass compile.
I can't think of a use case where overriding static functions (in Java) can be useful, but if you ever absolutely must achieve it, here's how:
import java.lang.reflect.Method;
class A {
public static void callOut() {
System.out.println("A.callOut");
}
}
public class B extends A {
public static void callOut() {
System.out.println("B.callOut");
}
public static void main(String[] args) throws Exception
{
A a = new A();
A b = new B();
Method aM = a.getClass().getMethod("callOut");
Method bM = b.getClass().getMethod("callOut");
aM.invoke(null); // prints A.callOut
bM.invoke(null); // prints B.callOut
}
}
Maybe you need to rethink you design, if you have a need to override the marshal method, then it shouldn't be static in the first place.

Categories

Resources