
io.muserver.rest.StringEntityProviders Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mu-server Show documentation
Show all versions of mu-server Show documentation
A simple but powerful web server framework
The newest version!
package io.muserver.rest;
import io.muserver.Mutils;
import io.netty.buffer.ByteBufUtil;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.QueryStringEncoder;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.ext.MessageBodyReader;
import jakarta.ws.rs.ext.MessageBodyWriter;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.*;
import java.time.format.DateTimeParseException;
import java.time.temporal.Temporal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static java.util.Arrays.asList;
class StringEntityProviders {
static final List stringEntityReaders = asList(
StringMessageReaderWriter.INSTANCE, new FormUrlEncodedReader(), new ReaderEntityReader(),
CharArrayReaderWriter.INSTANCE, TemporalEntityReaderWriter.INSTANCE
);
static final List stringEntityWriters = asList(
StringMessageReaderWriter.INSTANCE, CharArrayReaderWriter.INSTANCE, new FormUrlEncodedWriter(),
TemporalEntityReaderWriter.INSTANCE
);
@Produces({"text/plain;charset=utf-8", "*/*"})
@Consumes({"text/plain", "*/*"})
static class StringMessageReaderWriter implements MessageBodyWriter, MessageBodyReader {
private StringMessageReaderWriter() {
}
static final StringMessageReaderWriter INSTANCE = new StringMessageReaderWriter();
public boolean isWriteable(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return String.class.equals(type);
}
public long getSize(String s, Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
if (s.length() > 100000) {
return -1;
}
Charset charset = EntityProviders.charsetFor(mediaType);
if (charset.equals(StandardCharsets.UTF_8)) {
return ByteBufUtil.utf8Bytes(s);
}
return s.getBytes(charset).length;
}
public void writeTo(String s, Class> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
entityStream.write(s.getBytes(EntityProviders.charsetFor(mediaType)));
}
public boolean isReadable(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return String.class.equals(type);
}
public String readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
return new String(Mutils.toByteArray(entityStream, 2048), EntityProviders.charsetFor(mediaType));
}
}
@Produces({"text/plain;charset=utf-8", "*/*"})
@Consumes({"text/plain", "*/*"})
static class CharArrayReaderWriter implements MessageBodyWriter, MessageBodyReader {
private CharArrayReaderWriter() {
}
static final CharArrayReaderWriter INSTANCE = new CharArrayReaderWriter();
@Override
public boolean isReadable(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return type.isArray() && type.getComponentType().equals(char.class);
}
@Override
public char[] readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
InputStreamReader reader = new InputStreamReader(entityStream, EntityProviders.charsetFor(mediaType));
CharArrayWriter charArrayWriter = new CharArrayWriter();
char[] buffer = new char[2048];
int read;
while ((read = reader.read(buffer)) > -1) {
charArrayWriter.write(buffer, 0, read);
}
return charArrayWriter.toCharArray();
}
@Override
public boolean isWriteable(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return type.isArray() && type.getComponentType().equals(char.class);
}
@Override
public long getSize(char[] chars, Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
if (chars.length > 100000) {
return -1;
}
return new String(chars).getBytes(EntityProviders.charsetFor(mediaType)).length;
}
@Override
public void writeTo(char[] chars, Class> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
ByteBuffer bb = EntityProviders.charsetFor(mediaType).encode(CharBuffer.wrap(chars));
byte[] bytes = new byte[bb.remaining()];
bb.get(bytes);
entityStream.write(bytes);
Arrays.fill(bb.array(), (byte) 0); // if returning char[] arrays, it might be because it's a password etc, so blank it out
}
}
@Produces({"text/plain;charset=utf-8"})
@Consumes({"text/plain"})
static class TemporalEntityReaderWriter implements MessageBodyReader, MessageBodyWriter {
static final TemporalEntityReaderWriter INSTANCE = new TemporalEntityReaderWriter();
@Override
public boolean isReadable(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Temporal.class.isAssignableFrom(type);
}
@Override
public T readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
String s = new String(Mutils.toByteArray(entityStream, 512), EntityProviders.charsetFor(mediaType));
if (Mutils.nullOrEmpty(s)) {
return null;
}
try {
if (type.equals(Instant.class)) {
return (T) Instant.parse(s);
} else if (type.equals(LocalDate.class)) {
return (T) LocalDate.parse(s);
} else if (type.equals(LocalDateTime.class)) {
return (T) LocalDateTime.parse(s);
} else if (type.equals(LocalTime.class)) {
return (T) LocalTime.parse(s);
} else if (type.equals(ZonedDateTime.class)) {
return (T) ZonedDateTime.parse(s);
} else if (type.equals(OffsetDateTime.class)) {
return (T) OffsetDateTime.parse(s);
} else if (type.equals(OffsetTime.class)) {
return (T) OffsetTime.parse(s);
} else if (type.equals(Year.class)) {
return (T) Year.parse(s);
} else if (type.equals(YearMonth.class)) {
return (T) YearMonth.parse(s);
}
throw new BadRequestException("Unsupported temporal type " + type);
} catch (DateTimeParseException e) {
throw new BadRequestException("Invalid date format in request body", e);
}
}
@Override
public boolean isWriteable(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Temporal.class.isAssignableFrom(type);
}
@Override
public long getSize(T instant, Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return getBytes(instant, mediaType).length;
}
@Override
public void writeTo(T instant, Class> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
entityStream.write(getBytes(instant, mediaType));
}
static byte[] getBytes(Temporal instant, MediaType mediaType) {
if (instant == null) {
return new byte[0];
}
return instant.toString().getBytes(EntityProviders.charsetFor(mediaType));
}
}
@Consumes("*/*")
static class ReaderEntityReader implements MessageBodyReader {
public boolean isReadable(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Reader.class.isAssignableFrom(type);
}
public Reader readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
return new InputStreamReader(entityStream, EntityProviders.charsetFor(mediaType));
}
}
@Consumes("application/x-www-form-urlencoded")
static class FormUrlEncodedReader implements MessageBodyReader> {
@Override
public boolean isReadable(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return MultivaluedMap.class.isAssignableFrom(type);
}
@Override
public MultivaluedMap readFrom(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
String body = new String(Mutils.toByteArray(entityStream, 2048), EntityProviders.charsetFor(mediaType));
QueryStringDecoder formDecoder = new QueryStringDecoder(body, false);
Map> parameters = formDecoder.parameters();
MultivaluedHashMap form = new MultivaluedHashMap<>();
for (Map.Entry> entry : parameters.entrySet()) {
form.put(entry.getKey(), entry.getValue());
}
return form;
}
}
@Produces("application/x-www-form-urlencoded")
static class FormUrlEncodedWriter implements MessageBodyWriter> {
@Override
public boolean isWriteable(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return MultivaluedMap.class.isAssignableFrom(type);
}
@Override
public long getSize(MultivaluedMap stringStringMultivaluedMap, Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return -1;
}
@Override
public void writeTo(MultivaluedMap form, Class> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
QueryStringEncoder encoder = new QueryStringEncoder("");
for (Map.Entry> entry : form.entrySet()) {
for (String value : entry.getValue()) {
encoder.addParam(entry.getKey(), value);
}
}
entityStream.write(encoder.toString().substring(1).getBytes(EntityProviders.charsetFor(mediaType)));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy