public interface TestServiceIface {
default String test(String str, int flag) {
return str;
}
}
interface like this,if implements the interface, and have an instance ,how can I call default method? if use reflection, how to do?
And I only have this interface,no Impl class and no Impl instance.how to call the default method?
Or via a MethodHandle, but do notice that you actually need an implementation class of that interface:
static class Impl implements TestServiceIface {
}
And the usage:
MethodType methodType = MethodType.methodType(String.class, String.class, int.class);
MethodHandle handle = MethodHandles.lookup().findVirtual(TestServiceIface.class, "test", methodType);
String result = (String) handle.invoke(new Impl(), "test", 12);
System.out.println(result); // test
You can access interface default methods by reflection as below:
Class<TestServiceIface> type = TestServiceIface.class;
Method defaultMethod = type.getMethod("test", String.class, int.class);
String result = (String) defaultMethod.invoke(instance, "foo", 0);
However, if the subclass override the default method, then the overrided method will be called, which means interface default method also supports polymorphism.
Related
Background
I'm developing a Spring Boot application and I'm using Kotlin, IntelliJ and Gradle (Groovy). I have some enum class in my code and I need to persist them (with JPA). I used a simple global converter.
// Sample Enum
enum class Policy {
PUBLIC,
INVITE_ONLY
}
// Sample Converter
#Converter(autoApply = true)
class PolicyConverter : AttributeConverter<Policy, String> {
override fun convertToDatabaseColumn(attribute: Policy): String {
return attribute.name
}
override fun convertToEntityAttribute(dbData: String): Policy {
return Policy.valueOf(dbData.toUpperCase())
}
}
Problem
Since I have 5-6 enums and I hate duplicated code, I thought about a generic converter that should do the work for every given enum. I tried to code something, but nothing worked. This is what I was thinking about:
abstract class EnumConverter<E: Enum<E>> : AttributeConverter<E, String> {
override fun convertToDatabaseColumn(attribute: E): String {
return attribute.name
}
override fun convertToEntityAttribute(dbData: String): E {
return E.valueOf(dbData.toUpperCase())
}
}
In this way I can only extend from one abstract class every enum converter, like so:
#Converter(autoApply = true)
class PolicyConverter : EnumConverter<Policy>() {}
Problem with this code is that I have two errors:
E is red because: Type parameter 'E' cannot have or inherit a companion object, so it cannot be on the left hand side of dot
valueOf is red because: unresolved reference (there are like 150+ types of .valueOf).
As suggested from this I tried to use following function:
private inline fun <reified E : Enum<E>> getValue(string: String): E {
return enumValueOf(string.toUpperCase())
}
But when called from the .convertToEntityAttribute, the result is that "Cannot use 'E' as reified type parameter. Use a class instead."
Question
So the question is simple: how can I implement an easy and fast way to make one converter for all my enums, that all follows the same principle? I just need a return E.valueOf(<value>) function, but it's not present.
A simply workaround of this problem is to define an abstract method that every class will implement and it will return the correct type, given a string.
// Inside EnumConverter, the Generic Class
abstract class EnumConverter<E: Enum<E>> : AttributeConverter<E, String> {
abstract fun getValueFromString(string: String) : E
override fun convertToEntityAttribute(dbData: String): E {
return getValueFromString(dbData)
}
[...]
}
// Inside Policy Enum, implementing
class PolicyConverter : EnumConverter<Policy>() {
override fun getValueFromString(string: String): Policy {
return Policy.valueOf(string.toUpperCase())
}
}
But it's a workaround that I really dislike.
I'm attempting to use Spring's org.springframework.core.ResolvableType to figure out the parameterized type at runtime as such:
public class MyClass<T> implements MyInterface<T> {
private final Class<T> typeClass;
public CustomStateSerializer() {
ResolvableType type = ResolvableType.forClass(getClass());
ResolvableType genericType = type.getGeneric();
this.typeClass= (Class<T>) genericType.resolve();
}
}
...
new MyClass<MyType>();
Unfortunately, genericType results to ?. Clearly I'm not using it correctly and I can't seem to find any good docs for the solution.
The class is only has reference to which is not defined yet. So you can pass the instance that will have an specific already:
ResolvableType type = ResolvableType.forClass(getClass(), this);
this.typeClass = type.getGeneric(0).resolve();
In Java Method References
ContainingClass::staticMethodName - means that a class can refer the static method (Reference to a Static Method )
containingObject::instanceMethodName - means that a class object is created first and then that object is used to refer the instanceMethod .
My doubt is
ContainingType::methodName - what does the ContainingType mean ?
Is ContainingType a predefined class in java like String or something else ?
Java Language Specification, §4.3. Reference Types and Values:
There are four kinds of reference types: class types (§8.1), interface types (§9.1), type variables (§4.4), and array types (§10.1).
Array type don't have static methods, so that doesn't apply to static method reference, but you can do the other 3:
class MyClass {
static void doIt() {/*doing it*/}
}
interface MyInterface {
static void doIt() {/*doing it*/}
}
class Test<T extends MyClass> {
void test() {
Runnable m1 = MyClass::doIt; // class type
Runnable m2 = MyInterface::doIt; // interface type
Runnable m3 = T::doIt; // type variable
}
}
Now that link is provided in a comment, it says:
Reference to a static method
ContainingClass::staticMethodName
Reference to an instance method of a particular object
containingObject::instanceMethodName
Reference to an instance method of an arbitrary object of a particular type
ContainingType::methodName
Reference to a constructor
ClassName::new
Here, again, ContainingType refers to any of the 3 reference types mentioned above: Class, Interface, and Type Variable.
You can then make a method reference for any instance method of such a type.
class MyClass {
void doIt() {/*doing it*/}
}
interface MyInterface {
void doIt();
}
class Test<T extends MyClass> {
void test() {
Consumer<MyClass> m1 = MyClass::doIt;
Consumer<MyInterface> m2 = MyInterface::doIt;
Consumer<T> m3 = T::doIt;
}
}
https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
In the document you gave,there is a example of the ContainingType:
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
and explains:
The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b), where a and b are arbitrary names used to better describe this example. The method reference would invoke the method a.compareToIgnoreCase(b).
I think,the element of the stringArray dosen't have a name (eg: String s1 = "Barbara"),so you can't refer it by containingObject::instanceMethodName(eg:s1::compareToIgnoreCase). That's why it uses ContainingType.
I think your ContainingType::methodName is a general/common form of the 2 forms above...
Think about the below code. You can replace the <methodReference> width
InterfaceA::method (for ContainingType::methodName)
ClassA::method (for also ContainingType::methodName)
ClassB::instanceMethod (for ContainingObject::instanceMethodName) or
ClassB::staticMethod (for ContainingClass::staticMethodName)
to demonstrate the mentioned cases:
public class App {
interface InterfaceA {
String method();
}
static class ClassA implements InterfaceA {
public String method() {
return "ContainingType::methodName";
}
}
static class ClassB extends ClassA {
public String instanceMethod() {
return "ContainingObject::instanceMethodName";
}
public static String staticMethod(ClassB classB) {
return "ContainingClass::staticMethodName";
}
}
public static void main(String[] args) {
System.out.println(((Function<ClassB, String>) <methodReference>).apply(new ClassB()));
}
}
I have to consume a REST api which follows a common syntax across all retrievable objects:
baseUrl + domainObjectName + qualifier
E.g.
"http://myweb.com/api/" + "cities" + "/{id}"
I created a BaseDao for my data layer and I would like to set up in DAO instantiation the base url for each domain object (baseUrl + domainObjectName). The problem is I have my api Base url defined in the properties file (and would like to keep it that way), and it is not available in the DAO constructor.
This is what I have:
public abstract class BaseDao {
protected static final String ID_QUALIFIER = "/{id}";
protected String domainObjectName = "";
protected String doBaseUrl = "";
#Value("#{config['baseUrlRest']}")
public String apiBaseUrl;
public GenericDaoRestImpl(String domainObjectName) {
this.domainObjectName = domainObjectName;
this.doBaseUrl = apiBaseUrl + domainObjectName;
}
}
When my dao is instantiated, apiBaseUrl is still null, although after creation it is indeed injecting the baseUrl property.
Is there any way around this, like injecting the property as a static constant?
This happens because Java doesn't allow to set fields of a class before the constructor is called. So Spring can't inject the value. There are two solutions:
Pass the value to the constructor instead (example 1)
Use #PostConstruct (example 2)
Example 1:
public GenericDaoRestImpl(
#Value("#{config['baseUrlRest']}") String apiBaseUrl
String domainObjectName
) {
...
}
Example 2:
#Value("#{config['baseUrlRest']}")
public String apiBaseUrl;
public GenericDaoRestImpl(String domainObjectName) {
this.domainObjectName = domainObjectName;
}
#PostConstruct
public void init() {
this.domainObjectName = domainObjectName;
this.doBaseUrl = apiBaseUrl + domainObjectName;
}
I prefer the #PostConstruct because constructor injection eventually leads to constructors with many parameters which makes them unwieldy.
If you don't like it, your third option is using the builder pattern with a fluent interface.
If I declare a method :
public Car makeCar(#Named("carClassName") String carClassName){
//...
}
It seems that the compiler (eclipse) is unhappy (i.e. it won't let me call the class with no arguments).
How can I inject these parameters when I call this method , dynamically ? Is there a way to inject a call to a method ?
Solution 1: insert carClassName in the caller,
class Whatever {
private #Named("carClassName") String carClassName);
public void dosomething() {
...
Cat cat = makeCar(carclassName);
...
}
}
Solution 2: use a factory,
class CarFactory {
private #Named("carClassName") String carClassName);
public Car create() {
return makeCar(carClassName);
}
}
and inject it where needed.