How to adapt to changes in the API

I have a big project that depends on a specific library. One of these library classes identified the following methods:

public void until(final Predicate<T> isTrue) public <V> V until(Function<? super T, V> isTrue) { 

where Predicate and Function :

 com.google.common.base.Predicate<T> com.google.common.base.Function<? super T, V> 

In the latest version of this library, the above was changed and refactored by canceling (deleting) the public void until(final Predicate<T> isTrue) method and changing the second method as follows:

 public <V> V until(Function<? super T, V> isTrue) 

where is the function now java.util.function.Function<? super T, V> java.util.function.Function<? super T, V> .

As far as I understand, the above changes were made to fully support Java 8 functions and, in particular, lambda expressions.

Now to my question. Although I can convert all calls to until , which used an obsolete version of this method for the new structure, I am afraid that there are too many places where this method is called. Is there a way that I can continue to use the old (deprecated) method, perhaps by re-declaring it elsewhere or something like that? Any alternative solutions to this problem will be accepted with pleasure.

+5
source share
1 answer

IF , you don’t want to change the source code, one of the possible solutions is to copy the source code from the library, whose class has the until(Function) method in your source code. and then adding the remote code until(Predicate) to the source code. final code as below:

 package ???;//the package of the library which class have `until` method class ??? {//the class copied from the library which have `until` method <T> boolean until(Predicate<T> predicate){ return until(new Function<T,Boolean>(){ public Boolean apply(T value){ return predicate.apply(value); } }); } <T,R> R until(Function<T,R> function){ // the source code from the library } //... other source code from the library } 

ClassLoader load your class copied from the library, not from the library. since ClassLoader uses the delegation model to search for classes / resources, and AppClassLoader will always find the class in the classpath, and then external banners in turn:

The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader . When asked to search for a class or resource, an instance of ClassLoader delegates the search for the class or resource to its parent class loader before trying to find the class or resource itself. The virtual machine’s built-in class loader, called the bootstrap class loader, itself does not have a parent, but can serve as the parent of an instance of ClassLoader .

Another option is to write your own ClassLoader and then write a proxy to access your library class. this is useful if you cannot copy the outer class of the library, since it depends on many inner classes. for example, let's say you have a library class as shown below:

 public class Library<T> { private final List<T> items; public Library(T... items) { this.items = Arrays.asList(items); } public boolean exists(Function<? super T, Boolean> condition) { return items.stream().anyMatch(condition::apply); } } 

It then declares an interface to match the library class as follows:

 public interface LibraryAccess<T> { boolean exists(Function<? super T, Boolean> condition); } 

Last write your own class, overwrite the library class as shown below:

 public class Library<T> { private final LibraryAccess<T> library; public Library(T... items) { // create library from external jars by your own ClassLoader & reflect api library = LibraryAccess.newInstance(items); } public boolean exists(Predicate<? super T> condition) { return library.exists(condition::test); } public boolean exists(Function<? super T, Boolean> condition) { return library.exists(condition); } } 

all source and test code i checked in github.

+2
source

Source: https://habr.com/ru/post/1269139/


All Articles