I would like to make a set of utility classes that implement an interface. In order to do this, I will be using the singleton pattern. However, it would also be nice to be able to use those utility classes via static method calls. For example:
public interface IValidator<T> {
boolean isValid(T value);
}
public class StringValidator implements IValidator<String> {
public static final StringValidator instance = new StringValidator();
#Override
public boolean isValid(final String value) {
return true;
}
}
The above provides a singleton which enables me to call the utility methods using an interface, as follows:
// Use case #1
IValidator<String> validator1 = StringValidator.instance;
validator1.isValid("");
// Use case #2
StringValidator.instance.isValid("");
However, I would also like to be able to use StringValidator in the following, more succinct way:
// Use case #3: How can I also allow this syntax?
StringValidator.isValid("");
Is there a way in Java to make all three of the above syntaxes work without renaming the method? The only idea I had was to add a varargs parameter to the static definition, as follows:
public class StringValidator implements IValidator<String> {
public static final StringValidator instance = new StringValidator();
#Override
public boolean isValid(final String value) {
return StringValidator.isValid(value);
}
public static boolean isValid(final String value, final Object... ignored) {
return true;
}
}
However, that fails with the message "Cannot make a static reference to the non-static method isValid(String) from the type StringValidator". Again, is there some way to make the compiler allow all three of my use-case syntaxes? Thanks.
If the interface is a functional interface you could drop the singleton
public class StringValidator {
public static boolean isValid(final String value) {
return ...;
}
}
and whenever you need a instance of Validator<String> use a method handle to the static method:
IValidator<String> validator1 = StringValidator::isValid;
I figured out a way. Change the code to the following:
public interface IValidator<T> {
boolean isValid(T value, Object... ignored);
}
public class StringValidator implements IValidator<String> {
public static final StringValidator instance = new StringValidator();
#Override
public boolean isValid(final String value, final Object... ignored) {
return isValid(value);
}
public static boolean isValid(final String value) {
return true;
}
}
Then all three of the use cases compile. Java will generate a warning for use case #2, but that doesn't bother me as I think the only sane use of the implementing class are cases #1 and #3.
Related
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.
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.
I have a class library, that i didn't write, which defines several classes and subclasses, which have static methods. A very much stripped down example:
public class Vehicle {
static String getName() { return "unknown"; }
}
public class Car extends Vehicle {
static String getName() { return "car"; }
}
public class Train extends Vehicle {
static String getName() { return "train"; }
}
Now, i have an object, which is a Vehicle, may be a Car or a Train, and want to call it's getName() function. Again, very much stripped down:
public class SMCTest {
public static void main(String[] args) {
Vehicle vehicle=new Car();
System.out.println(vehicle.getName());
}
}
This prints "unknown", not "car", as the JVM doesn't need, or use, the object to call a static method, it just uses the class.
If that was my code, i'd rewrite vehicle library to use singletons, and non-static methods, but as it isn't my code, i'd rather not touch it.
Is there any way to call the static method of the "real" class of the object, preferable without using reflection? If it helps, i could change the vehicle in the above example to a Class <? extends Vehicle> variable and use that, but i don't see how that helps me to avoid reflection.
preferable without using reflection?
Drop that requirement, and:
vehicle.getClass().getMethod("getName").invoke(null);
would solve the problem as asked.
(However, you should fix the code.)
There is no need for reflection if you know all of the classes involved. With java 8 (create the necessary interface and (anonymous) classes for lower java versions):
public class VehicleUtil {
private static final Map<Class<? extends Vehicle>, Supplier<String>> map = createMap();
private static Map<Class<? extends Vehicle>, Supplier<String>> createMap() {
Map<Class<? extends Vehicle>, Supplier<String>> result = new HashMap<>();
result.put(Vehicle.class, Vehicle::getName);
result.put(Car.class, Car::getName);
result.put(Train.class, Train::getName);
return result;
}
public static String getName(Vehicle vehicle) {
return map.get(vehicle.getClass()).get();
}
public static void main(String[] args) {
System.out.println(VehicleUtil.getName(new Vehicle()));
System.out.println(VehicleUtil.getName(new Car()));
System.out.println(VehicleUtil.getName(new Train()));
}
}
The above is just a more elegant way of doing something like:
public static String getName(Vehicle vehicle) {
return Vehicle.class.equals(vehicle.getClass()) ? Vehicle.getName()
: Car.class.equals(vehicle.getClass()) ? Car.getName()
: Train.class.equals(vehicle.getClass()) ? Train.getName()
: null;
}
I'd like to access a static method on a class, but have that class passed in a generic.
I've done the following:
class Base{
public static String getStaticName(){
return "Base";
}
}
class Child extends Base{
public static String getStaticName(){
return "Child";
}
}
class StaticAccessor{
public static <T extends Base>String getName(Class<T> clazz){
return T.getStaticName();
}
}
StaticAccessor.getName() // --> "Base"
This will return "Base" but what i'd like is "Child" anybody a suggestion without reflections?
You can't do that without reflection, because the type T is erased at runtime (meaning it will be reduced to its lower bound, which is Base).
Since you do have access to a Class<T> you can do it with reflection, however:
return (String) clazz.getMethod("getStaticName").invoke(null);
Note that I'd consider such code to be code smell and that it is pretty fragile. Could you tell us why you need that?
If it is OK for you to pass an object instance rather than Class in your static accessor, then, there is a simple and elegant solution:
public class Test {
static class Base {
public static String getStaticName() { return "Base"; }
public String myOverridable() { return Base.getStaticName(); };
}
static class Child extends Base {
public static String getStaticName() { return "Child"; }
#Override
public String myOverridable() { return Child.getStaticName(); };
}
static class StaticAccessor {
public static <T extends Base>String getName(T instance) {
return instance.myOverridable();
}
}
public static void main(String[] args) {
Base b = new Base();
Child c = new Child();
System.out.println(StaticAccessor.getName(b));
System.out.println(StaticAccessor.getName(c));
}
}
The output is:
Base
Child
I don't believe you can do this without reflection.
It appears you should be doing is not using static methods. You are using inheritance but static methods do not follow inheritance rules.
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