Cómo envolver un java.lang.Appendable en un java.io.Writer?
outputstream write java (3)
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 redireccionando todos los métodos de write
directamente a los métodos de append
en el Appendable
no tendrás que preocuparte por flush()
y close()
menos que tus implementos se Appendable
y / o Flushable
.
Un buen ejemplo es algo así como BufferedWriter . Cuando llame a write()
sobre eso, es posible que no envíe todos los bytes a la salida / secuencia final inmediatamente. Es posible que algunos bytes no se envíen hasta que lo flush()
o lo 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 .
Aquí está lo que probablemente sea una buena implementación para este adaptador: http://pastebin.com/GcsxqQxj
UPDATE2: Mi propia versión de la clase de adaptador, que solo llama a instanceof
en el constructor y utiliza un delta (Java 1.5) en las funciones flush()
y close()
(evitando la necesidad de reflexión o lógica después de la construcción del objeto), incluido en la parte inferior de esta publicación. 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 acepta un apéndice y lo pasa a la función de escritura original.
Veo que puede extender Writer
, que es abstracto, y redirigir todas las funciones de write(...)
a sus correspondientes append(...)
-s. Pero también debe implementar flush()
y close()
, y no tengo ningún problema en cómo escribirlos limpiamente para que este wrapper-class pueda aceptar cualquier Appendable.
Me sorprende que no haya nada por ahí, ya sea en la web o stackoverflow, o en una biblioteca existente, que solucione esto. Al menos no que yo pueda encontrar.
Agradecería una pequeña guía aquí. Gracias.
Código de 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 reflejo después de la construcción del objeto. Esto también se publicó como una idea central : https://gist.github.com/aliteralmind/8494917
Esta clase contiene una demostración, seguida de dos deltas sin Flushable
(uno que se puede Flushable
, uno 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;
/**
<P>{@code java NewWriterForAppendable}.</P>
**/
public class NewWriterForAppendable {
/**
<P>Demonstrates {@code newWriterForAppendable(apbl)} for creating a new {@code Writer} that wraps around {@code System.out} (writes to the console).</P>
**/
public static final void main(String[] igno_red) {
try {
NewWriterForAppendable.newWriterForAppendable(System.out).write("hello");
} catch(IOException iox) {
throw new RuntimeException("WriterForAppendableXmpl", iox);
}
}
/**
<P>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.</P>
@see #newWriterForAppendable(Appendable) newWriterForAppendable(apbl)
**/
public static final Flushable FLUSHABLE_DO_NOTHING = new Flushable() {
public void flush() {
}
};
/**
<P>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.</P>
@see #newWriterForAppendable(Appendable) newWriterForAppendable(apbl)
**/
public static final Closeable CLOSEABLE_DO_NOTHING = new Closeable() {
public void close() {
}
};
/**
<P>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.</P>
<P>This function is released as a <A HREF="https://gist.github.com/aliteralmind/8494917">gist</A>, and is an example of the <A HREF="http://en.wikipedia.org/wiki/Adapter_pattern#Object_Adapter_pattern">Object Adapter pattern</A>. Thanks to <A HREF="http://stackoverflow.com/users/1211906/marc-baumbach">Marc Baumbach</A> on <A HREF="http://stackoverflow.com">{@code stackoverflow}</A> for the assistance. See (viewed 1/18/2014)
<BR> <CODE><A HREF="http://stackoverflow.com/questions/21200421/how-to-wrap-a-java-lang-appendable-into-a-java-io-writer">http://stackoverflow.com/questions/21200421/how-to-wrap-a-java-lang-appendable-into-a-java-io-writer</A></CODE></P>
@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();
}
}
Puede aceptar cualquier Appendable
y luego verificar si es un Writer
mediante instanceof
. Luego realice un downcast y llame 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