J'ai ce InputStream:
InputStream inputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));
Comment puis-je convertir cela en ServletInputStream?
J'ai essayé:
ServletInputStream servletInputStream = (ServletInputStream) inputStream;
mais ne travaille pas.
MODIFIER:
Ma méthode est la suivante:
private static class LowerCaseRequest extends HttpServletRequestWrapper {
public LowerCaseRequest(final HttpServletRequest request) throws IOException, ServletException {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
ServletInputStream servletInputStream;
StringBuilder jb = new StringBuilder();
String line;
String toLowerCase = "";
BufferedReader reader = new BufferedReader(new InputStreamReader(super.getInputStream()));
while ((line = reader.readLine()) != null) {
toLowerCase = jb.append(line).toString().toLowerCase();
}
InputStream inputStream = new ByteArrayInputStream(toLowerCase.getBytes(StandardCharsets.UTF_8));
servletInputStream = (ServletInputStream) inputStream;
return servletInputStream;
}
}
J'essaie de convertir toute ma demande en minuscule.
Essayez ce code.
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));
ServletInputStream servletInputStream=new ServletInputStream(){
public int read() throws IOException {
return byteArrayInputStream.read();
}
}
Mon conseil: ne créez pas la ByteArrayInputStream
, utilisez simplement le tableau d'octets que vous avez déjà obtenu avec la méthode getBytes
. Cela devrait suffire à créer une ServletInputStream
.
Malheureusement, la réponse de aksappy ne remplace que la méthode read
. Bien que cela puisse suffire dans Servlet API 3.0 et versions ultérieures, il existe dans les versions ultérieures de l'API Servlet des méthodes three more que vous devez implémenter.
Voici mon implémentation de la classe, bien qu’elle devienne assez longue (en raison des nouvelles méthodes introduites dans l’API Servlet 3.1), vous voudrez peut-être envisager de la factoriser dans une classe imbriquée ou même de niveau supérieur.
final byte[] myBytes = myString.getBytes("UTF-8");
ServletInputStream servletInputStream = new ServletInputStream() {
private int lastIndexRetrieved = -1;
private ReadListener readListener = null;
@Override
public boolean isFinished() {
return (lastIndexRetrieved == myBytes.length-1);
}
@Override
public boolean isReady() {
// This implementation will never block
// We also never need to call the readListener from this method, as this method will never return false
return isFinished();
}
@Override
public void setReadListener(ReadListener readListener) {
this.readListener = readListener;
if (!isFinished()) {
try {
readListener.onDataAvailable();
} catch (IOException e) {
readListener.onError(e);
}
} else {
try {
readListener.onAllDataRead();
} catch (IOException e) {
readListener.onError(e);
}
}
}
@Override
public int read() throws IOException {
int i;
if (!isFinished()) {
i = myBytes[lastIndexRetrieved+1];
lastIndexRetrieved++;
if (isFinished() && (readListener != null)) {
try {
readListener.onAllDataRead();
} catch (IOException ex) {
readListener.onError(ex);
throw ex;
}
}
return i;
} else {
return -1;
}
}
};
En fonction de vos besoins, vous pouvez également vouloir remplacer d'autres méthodes. Comme Romfret l'a souligné, il est conseillé de remplacer certaines méthodes, telles que close
et available
. Si vous ne les implémentez pas, le flux signalera toujours qu'il y a 0 octet à lire, et la méthode close
n'affectera en rien l'état du flux. Vous pouvez probablement vous en sortir sans surcharger skip
, car l'implémentation par défaut appellera simplement read
plusieurs fois.
@Override
public int available() throws IOException {
return (myBytes.length-lastIndexRetrieved-1);
}
@Override
public void close() throws IOException {
lastIndexRetrieved = myBytes.length-1;
}
Malheureusement, en raison de la nature d'une classe anonyme, il vous sera difficile d'écrire une méthode close
efficace car, tant qu'une instance du flux n'a pas été collectée par Java, elle conserve une référence au tableau d'octets. , même si le flux a été fermé.
Cependant, si vous factorisez la classe dans une classe imbriquée ou de niveau supérieur (ou même une classe anonyme avec un constructeur appelé à partir de la ligne dans laquelle elle est définie), la variable myBytes
peut être un champ non final plutôt qu'un champ. variable locale finale, et vous pouvez ajouter une ligne comme celle-ci:
myBytes = null;
à votre méthode close
, qui permettra à Java de libérer de la mémoire occupée par le tableau d'octets.
Bien sûr, cela vous obligera à écrire un constructeur, tel que:
private byte[] myBytes;
public StringServletInputStream(String str) {
try {
myBytes = str.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("JVM did not support UTF-8", e);
}
}
Vous pouvez également vouloir remplacer mark
, markSupported
et reset
si vous souhaitez prendre en charge mark/reset. Cependant, je ne suis pas sûr qu'ils soient effectivement appelés par votre conteneur.
private int readLimit = -1;
private int markedPosition = -1;
@Override
public boolean markSupported() {
return true;
}
@Override
public synchronized void mark(int readLimit) {
this.readLimit = readLimit;
this.markedPosition = lastIndexRetrieved;
}
@Override
public synchronized void reset() throws IOException {
if (markedPosition == -1) {
throw new IOException("No mark found");
} else {
lastIndexRetrieved = markedPosition;
readLimit = -1;
}
}
// Replacement of earlier read method to cope with readLimit
@Override
public int read() throws IOException {
int i;
if (!isFinished()) {
i = myBytes[lastIndexRetrieved+1];
lastIndexRetrieved++;
if (isFinished() && (readListener != null)) {
try {
readListener.onAllDataRead();
} catch (IOException ex) {
readListener.onError(ex);
throw ex;
}
readLimit = -1;
}
if (readLimit != -1) {
if ((lastIndexRetrieved - markedPosition) > readLimit) {
// This part is actually not necessary in our implementation
// as we are not storing any data. However we need to respect
// the contract.
markedPosition = -1;
readLimit = -1;
}
}
return i;
} else {
return -1;
}
}
Vous pouvez seulement lancer quelque chose comme ceci:
ServletInputStream servletInputStream = (ServletInputStream) inputStream;
si le inputStream que vous essayez de convertir est déjà un ServletInputStream. Il se plaindra s'il s'agit d'une autre implémentation de InputStream. Vous ne pouvez pas lancer un objet sur quelque chose qu'il n'est pas.
Dans un conteneur Servlet, vous pouvez obtenir un ServletInputStream à partir d'un ServletRequest:
ServletInputStream servletInputStream = request.getInputStream();
Alors, qu'essayez-vous réellement de faire?
MODIFIER
Je suis intrigué par la raison pour laquelle vous souhaitez convertir votre requête en minuscule. Pourquoi ne pas simplement rendre votre servlet insensible à la casse? En d'autres termes, votre code pour mettre en minuscule les données de la demande peut être copié dans votre servlet, il peut alors le traiter là-bas ... cherchez toujours la solution la plus simple!