com.rt.storage.api.client.http.UrlEncodedParser Maven / Gradle / Ivy
package com.rt.storage.api.client.http;
import com.rt.storage.api.client.util.ArrayValueMap;
import com.rt.storage.api.client.util.Charsets;
import com.rt.storage.api.client.util.ClassInfo;
import com.rt.storage.api.client.util.Data;
import com.rt.storage.api.client.util.FieldInfo;
import com.rt.storage.api.client.util.GenericData;
import com.rt.storage.api.client.util.ObjectParser;
import com.rt.storage.api.client.util.Preconditions;
import com.rt.storage.api.client.util.Throwables;
import com.rt.storage.api.client.util.Types;
import com.rt.storage.api.client.util.escape.CharEscapers;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* Implements support for HTTP form content encoding parsing of type {@code
* application/x-www-form-urlencoded} as specified in the HTML 4.0
* Specification.
*
* Implementation is thread-safe.
*
*
The data is parsed using {@link #parse(String, Object)}.
*
*
Sample usage:
*
*
* static void setParser(HttpTransport transport) {
* transport.addParser(new UrlEncodedParser());
* }
*
*
* @since 1.0
* @author Yaniv Inbar
*/
public class UrlEncodedParser implements ObjectParser {
/** {@code "application/x-www-form-urlencoded"} content type. */
public static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
/**
* {@code "application/x-www-form-urlencoded"} media type with UTF-8 encoding.
*
* @since 1.13
*/
public static final String MEDIA_TYPE =
new HttpMediaType(UrlEncodedParser.CONTENT_TYPE).setCharsetParameter(Charsets.UTF_8).build();
/**
* Parses the given URL-encoded content into the given data object of data key name/value pairs
* using {@link #parse(Reader, Object)}.
*
* @param content URL-encoded content or {@code null} to ignore content
* @param data data key name/value pairs
*/
public static void parse(String content, Object data) {
parse(content, data, true);
}
/**
* Parses the given URL-encoded content into the given data object of data key name/value pairs
* using {@link #parse(Reader, Object)}.
*
* @param content URL-encoded content or {@code null} to ignore content
* @param data data key name/value pairs
* @param decodeEnabled flag that specifies whether decoding should be enabled.
*/
public static void parse(String content, Object data, boolean decodeEnabled) {
if (content == null) {
return;
}
try {
parse(new StringReader(content), data, decodeEnabled);
} catch (IOException exception) {
// I/O exception not expected on a string
throw Throwables.propagate(exception);
}
}
/**
* Parses the given URL-encoded content into the given data object of data key name/value pairs,
* including support for repeating data key names.
*
* Declared fields of a "primitive" type (as defined by {@link Data#isPrimitive(Type)} are
* parsed using {@link Data#parsePrimitiveValue(Type, String)} where the {@link Class} parameter
* is the declared field class. Declared fields of type {@link Collection} are used to support
* repeating data key names, so each member of the collection is an additional data key value.
* They are parsed the same as "primitive" fields, except that the generic type parameter of the
* collection is used as the {@link Class} parameter.
*
*
If there is no declared field for an input parameter name, it will be ignored unless the
* input {@code data} parameter is a {@link Map}. If it is a map, the parameter value will be
* stored either as a string, or as a {@link ArrayList}<String> in the case of repeated
* parameters.
*
* @param reader URL-encoded reader
* @param data data key name/value pairs
* @since 1.14
*/
public static void parse(Reader reader, Object data) throws IOException {
parse(reader, data, true);
}
/**
* Parses the given URL-encoded content into the given data object of data key name/value pairs,
* including support for repeating data key names.
*
*
Declared fields of a "primitive" type (as defined by {@link Data#isPrimitive(Type)} are
* parsed using {@link Data#parsePrimitiveValue(Type, String)} where the {@link Class} parameter
* is the declared field class. Declared fields of type {@link Collection} are used to support
* repeating data key names, so each member of the collection is an additional data key value.
* They are parsed the same as "primitive" fields, except that the generic type parameter of the
* collection is used as the {@link Class} parameter.
*
*
If there is no declared field for an input parameter name, it is ignored unless the input
* {@code data} parameter is a {@link Map}. If it is a map, the parameter value is stored either
* as a string, or as a {@link ArrayList}<String> in the case of repeated parameters.
*
* @param reader URL-encoded reader
* @param data data key name/value pairs
* @param decodeEnabled flag that specifies whether data should be decoded.
* @since 1.14
*/
public static void parse(Reader reader, Object data, boolean decodeEnabled) throws IOException {
Class> clazz = data.getClass();
ClassInfo classInfo = ClassInfo.of(clazz);
List context = Arrays.asList(clazz);
GenericData genericData = GenericData.class.isAssignableFrom(clazz) ? (GenericData) data : null;
@SuppressWarnings("unchecked")
Map