¿Cómo envolver un java.lang.Appendable en un java.io.Writer?

ACTUALIZACIÓN2: Mi propia versión de la clase de adaptador, que solo llama instanceof en el constructor y usa un delta (Java 1.5) en las funciones flush() y close() (evitando la necesidad de cualquier reflexión o lógica después de la construcción del objeto), es Incluido en la parte inferior de este post. ACTUALIZACIÓN1: Marc Baumbach escribió un Adaptador simple que es exactamente lo que necesito. Incluido a continuación. La pregunta original sigue.


Una función que requiere un java.lang.Appendable puede aceptar un java.io.Writer , porque Writer implementa Appendable .

¿Qué acerca del otro camino alrededor? Estoy usando una función que requiere un escritor, y estoy tratando de crear otra función que lo llame, que acepte un apéndice y lo pase a la función de escritor original.

Veo que puede extender Writer , que es abstracto, y redirigir todas las funciones write(...) a sus correspondientes append(...) -s. Pero también tienes que implementar flush() y close() , y tengo claro cómo escribirlos de manera limpia para que esta clase de envoltura pueda aceptar cualquier anexo.

Me sorprende que no haya nada ya disponible, ya sea en la web o en stackoverflow, o en una biblioteca existente, que aborde esto. Al menos no que yo pueda encontrar.

Agradecería una pequeña guía aquí. Gracias.


Código adaptador que responde a esta pregunta. Escrito por Marc Baumbach (mi propia versión está abajo):

 import java.io.Closeable; import java.io.Flushable; import java.io.IOException; import java.io.Writer; public class AppendableWriterAdapter extends Writer { private Appendable appendable; public AppendableWriterAdapter(Appendable appendable) { this.appendable = appendable; } @Override public void write(char[] cbuf, int off, int len) throws IOException { appendable.append(String.valueOf(cbuf), off, len); } @Override public void flush() throws IOException { if (appendable instanceof Flushable) { ((Flushable) appendable).flush(); } } @Override public void close() throws IOException { flush(); if (appendable instanceof Closeable) { ((Closeable) appendable).close(); } } } 

Aquí está mi propia versión, basada en la de Marc, que solo usa instanceof solo en el constructor, y un delta (Java 1.5) en flush() y close() . Esto es para evitar tener que usar cualquier lógica o reflexión después de la construcción del objeto. Esto también se publica como un gist : https://gist.github.com/aliteralmind/8494917

Esta clase contiene una demostración, seguida de dos deltas de no hacer nada (uno que se puede Flushable , otro que se puede Closeable ), la función principal ( newWriterForAppendable(apbl) ) y luego la clase del adaptador.

  import java.io.Closeable; import java.io.Flushable; import java.io.IOException; import java.io.Writer; /** 

{@code java NewWriterForAppendable}.

**/ public class NewWriterForAppendable { /**

Demonstrates {@code newWriterForAppendable(apbl)} for creating a new {@code Writer} that wraps around {@code System.out} (writes to the console).

**/ public static final void main(String[] igno_red) { try { NewWriterForAppendable.newWriterForAppendable(System.out).write("hello"); } catch(IOException iox) { throw new RuntimeException("WriterForAppendableXmpl", iox); } } /**

A {@code Flushable} whose {@code flush()} function does nothing. This is used by {@link #newWriterForAppendable(Appendable ap_bl) newWriterForAppendable}{@code (apbl)} as a (Java 1.5) delta.

@see #newWriterForAppendable(Appendable) newWriterForAppendable(apbl) **/ public static final Flushable FLUSHABLE_DO_NOTHING = new Flushable() { public void flush() { } }; /**

A {@code Closeable} whose {@code close()} function does nothing. This is used by {@link #newWriterForAppendable(Appendable ap_bl) newWriterForAppendable}{@code (apbl)} as a (Java 1.5) delta.

@see #newWriterForAppendable(Appendable) newWriterForAppendable(apbl) **/ public static final Closeable CLOSEABLE_DO_NOTHING = new Closeable() { public void close() { } }; /**

Creates a new {@code java.io.Writer} that wraps around a {@code java.lang.Appendable}. It properly {@link java.io.Writer#flush() flush}es and {@link java.io.Writer#close() close}s appendables that happened to also be {@link java.io.Flushable}s and/or {@link java.io.Closeable Closeable}s. This uses {@code instanceof} only in the constructor, and a delta in {@code flush()} and {@code close()}, which avoids having to use any logic or reflection after object construction.

This function is released as a gist, and is an example of the Object Adapter pattern. Thanks to Marc Baumbach on {@code stackoverflow} for the assistance. See (viewed 1/18/2014)
    http://stackoverflow.com/questions/21200421/how-to-wrap-a-java-lang-appendable-into-a-java-io-writer

@return A new writer that uses an appendable to do its output. @see #FLUSHABLE_DO_NOTHING @see #CLOSEABLE_DO_NOTHING **/ public static final Writer newWriterForAppendable(Appendable ap_bl) { return (new WFA(ap_bl)); } private NewWriterForAppendable() { throw new IllegalStateException("constructor: Do not instantiate."); } } class WFA extends Writer { private final Appendable apbl; private final Flushable flbl; private final Closeable clbl; public WFA(Appendable ap_bl) { if(ap_bl == null) { throw new NullPointerException("ap_bl"); } apbl = ap_bl; //Avoids instanceof at every call to flush() and close() flbl = (Flushable)((ap_bl instanceof Flushable) ? ap_bl : NewWriterForAppendable.FLUSHABLE_DO_NOTHING); clbl = (Closeable)((ap_bl instanceof Closeable) ? ap_bl : NewWriterForAppendable.CLOSEABLE_DO_NOTHING); } @Override public void write(char[] a_c, int i_ndexStart, int i_ndexEndX) throws IOException { apbl.append(String.valueOf(a_c), i_ndexStart, i_ndexEndX); } @Override public Writer append(char c_c) throws IOException { apbl.append(c_c); return this; } @Override public Writer append(CharSequence c_q) throws IOException { apbl.append(c_q); return this; } @Override public Writer append(CharSequence c_q, int i_ndexStart, int i_ndexEndX) throws IOException { apbl.append(c_q, i_ndexStart, i_ndexEndX); return this; } @Override public void flush() throws IOException { flbl.flush(); } @Override public void close() throws IOException { flush(); clbl.close(); } }

Normalmente en un Writer , el flush() y close() están ahí para limpiar cualquier escritura adicional que no se haya confirmado o enviado a la transmisión. Simplemente redirigiendo todos los métodos de write directamente a los métodos de Appendable en el Appendable , no tendrá que preocuparse por flush() y close() menos que su Appendable implemente Appendable y / o Flushable .

Un buen ejemplo es algo así como BufferedWriter . Cuando está llamando a write() en eso, puede que no esté enviando todos los bytes a la salida / flujo final inmediatamente. Es posible que algunos bytes no se envíen hasta que usted los flush() o close() . Para estar absolutamente seguro, probaría el Appendable envuelto si es Flushable o Flushable en el método correspondiente y lo Flushable y realizaré la acción también.

Este es un patrón de diseño bastante estándar llamado patrón de adaptador .

Esto es lo que probablemente sea una buena implementación para este adaptador: http://pastebin.com/GcsxqQxj

Puede aceptar cualquier Appendable y luego verificar si es un Writer través de instanceof . Luego haz un downcast y llama a esa función que solo acepta Writer .

ejemplo:

 public void myMethod(Appendable app) throws InvalidAppendableException { if (app instanceof Writer) { someObj.thatMethod((Writer) app); } else { throw new InvalidAppendableException(); } } 

Google’s Guava tiene una utilidad simple para hacer esto: CharStreams.asWriter

La implementación no es la más rápida ( ver ), si quieres el mejor rendimiento, es posible que desees consultar spf4j Streams.asWriter

    Intereting Posts