The previous article deals with basic I/O transmission, and we often need to do other things. It may be necessary to count the amount of data transmitted, filter the data, or perform a log for every 1000 pieces of data, or to check what operations are being performed. Since the input and output have been separated, these tasks become simple insertion of some logic in the coordination code of the input and output. Most of the coordination code has similar functions, which can be put into standard tools and methods for ease of use.
The first standard modifier is a filter. Specification is used for implementation.
public interface Specification<T> { boolean test(T item);}
From the previous article, we can see that the last operation is
Inputs.text(source).transferTo(Outputs.text(destination));
To do other things, you can only enhance the output. Because both sender and consumer er are called through them, they need to be enhanced in the same way.
public class Filters { static class SpecificationOutputWrapper<T, ReceiverThrowableType extends Throwable> implements Output<T, ReceiverThrowableType> { final Output<T, ReceiverThrowableType> output; final Specification<T> specification; public SpecificationOutputWrapper(Output<T, ReceiverThrowableType> output, Specification<T> specification) { this.output = output; this.specification = specification; } public <SenderThrowableType extends Throwable> void receiveFrom(Sender<T, SenderThrowableType> sender) throws ReceiverThrowableType, SenderThrowableType { output.receiveFrom(new SpecificationSenderWrapper<T, SenderThrowableType>(sender, specification)); } } static class SpecificationSenderWrapper<T, SenderThrowableType extends Throwable> implements Sender<T, SenderThrowableType> { final Sender<T, SenderThrowableType> sender; final Specification<T> specification; public SpecificationSenderWrapper(Sender<T, SenderThrowableType> sender, Specification<T> specification) { this.sender = sender; this.specification = specification; } public <ReceiverThrowableType extends Throwable> void sendTo(Receiver<T, ReceiverThrowableType> receiver) throws ReceiverThrowableType, SenderThrowableType { sender.sendTo(new SpecificationReceiverWrapper<T, ReceiverThrowableType>(receiver, specification)); } } static class SpecificationReceiverWrapper<T, ReceiverThrowableType extends Throwable> implements Receiver<T, ReceiverThrowableType> { final Receiver<T, ReceiverThrowableType> receiver; final Specification<T> specification; public SpecificationReceiverWrapper(Receiver<T, ReceiverThrowableType> receiver, Specification<T> specification) { this.receiver = receiver; this.specification = specification; } public void receive(T item) throws ReceiverThrowableType { if(specification.test(item)) { receiver.receive(item); } } public void finished() throws ReceiverThrowableType { receiver.finished(); } } public static <T, ReceiverThrowableType extends Throwable> Output<T, ReceiverThrowableType> filter(Specification<T> specification, final Output<T, ReceiverThrowableType> output) { return new SpecificationOutputWrapper<T, ReceiverThrowableType>(output, specification); }}
Test code:
Public class demo_intercept_filterline {public static void main (string [] ARGs) throws ioexception {File Source = new file ("in"); file destination = new file ("out "); input <string, ioexception> input = inputs. text (source); Output <string, ioexception> output = outputs. text (destination); specification <string> specification = new specification <string> () {public Boolean test (string item) {If (item. trim (). length () = 0) return false; // filter empty rows return true ;}}; input. transferto (filters. filter (specification, output ));}}
The second common operation is to map data from one type to another. It means that the data types of input and output must be different, and there is a way to map the input data type to the output data type. The following example maps a string to a jsonobject and first defines the conversion method:
public interface Function<From, To> { /** * @return return the transformed data. {@code null} to indicate ignore the input data. */ To map(From from);}
The rest is basically similar to the above
public class FunctionFilter { private FunctionFilter(){} static class FunctionOutputWrapper<From, To, ReceiverThrowableType extends Throwable> implements Output<From, ReceiverThrowableType> { final Output<To, ReceiverThrowableType> output; final Function<From, To> function; public FunctionOutputWrapper(Output<To, ReceiverThrowableType> output, Function<From, To> function) { this.output = output; this.function = function; } public <SenderThrowableType extends Throwable> void receiveFrom(Sender<From, SenderThrowableType> sender) throws ReceiverThrowableType, SenderThrowableType { output.receiveFrom(new FunctionSenderWrapper<From, To, SenderThrowableType>(sender, function)); } } static class FunctionSenderWrapper<From, To, SenderThrowableType extends Throwable> implements Sender<To, SenderThrowableType> { final Sender<From, SenderThrowableType> sender; final Function<From, To> function; public FunctionSenderWrapper(Sender<From, SenderThrowableType> sender, Function<From, To> function) { this.sender = sender; this.function = function; } public <ReceiverThrowableType extends Throwable> void sendTo(Receiver<To, ReceiverThrowableType> receiver) throws ReceiverThrowableType, SenderThrowableType { sender.sendTo(new FunctionReceiverWrapper<From, To, ReceiverThrowableType>(receiver, function)); } } static class FunctionReceiverWrapper<From, To, ReceiverThrowableType extends Throwable> implements Receiver<From, ReceiverThrowableType> { final Receiver<To, ReceiverThrowableType> receiver; final Function<From, To> function; public FunctionReceiverWrapper(Receiver<To, ReceiverThrowableType> receiver, Function<From, To> function) { this.receiver = receiver; this.function = function; } public void receive(From item) throws ReceiverThrowableType { receiver.receive(function.map(item)); } public void finished() throws ReceiverThrowableType { receiver.finished(); } } public static <From, To, ReceiverThrowableType extends Throwable> Output<From, ReceiverThrowableType> filter(Function<From, To> function, final Output<To, ReceiverThrowableType> output) { return new FunctionOutputWrapper<From, To, ReceiverThrowableType>(output, function); }}
Test code:
public class Demo_Intercept_CountLine { public static void main(String[] args) throws IOException { File source = new File("in"); File destination = new File("out"); final AtomicInteger count = new AtomicInteger(); Input<String, IOException> input = Inputs.text(source); Output<String, IOException> output = Outputs.text(destination); Function<String, String> function = new Function<String, String>() { public String map(String from) { count.incrementAndGet(); return from; } }; input.transferTo(FunctionFilter.filter(function, output)); System.out.println("Counter: " + count.get()); }}
Reprinted from: https://github.com/oldratlee/io-api/wiki/generic-io-api-in-java-and-api-design