All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.juneau.urlencoding.UrlEncodingSerializer Maven / Gradle / Ivy

There is a newer version: 9.0.1
Show newest version
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
// * with the License.  You may obtain a copy of the License at                                                              *
// *                                                                                                                         *
// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
// *                                                                                                                         *
// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
// * specific language governing permissions and limitations under the License.                                              *
// ***************************************************************************************************************************
package org.apache.juneau.urlencoding;

import static org.apache.juneau.internal.StringUtils.*;

import java.io.*;
import java.net.*;

import org.apache.juneau.*;
import org.apache.juneau.serializer.*;
import org.apache.juneau.uon.*;

/**
 * Serializes POJO models to URL-encoded notation with UON-encoded values (a notation for URL-encoded query paramter values).
 *
 * 
Media types:
* * Handles Accept types: application/x-www-form-urlencoded *

* Produces Content-Type types: application/x-www-form-urlencoded * *

Description:
* * This serializer provides several serialization options. Typically, one of the predefined DEFAULT serializers will be sufficient. * However, custom serializers can be constructed to fine-tune behavior. * *

* The following shows a sample object defined in Javascript: *

* { * id: 1, * name: 'John Smith', * uri: 'http://sample/addressBook/person/1', * addressBookUri: 'http://sample/addressBook', * birthDate: '1946-08-12T00:00:00Z', * otherIds: null, * addresses: [ * { * uri: 'http://sample/addressBook/address/1', * personUri: 'http://sample/addressBook/person/1', * id: 1, * street: '100 Main Street', * city: 'Anywhereville', * state: 'NY', * zip: 12345, * isCurrent: true, * } * ] * } *

* *

* Using the "strict" syntax defined in this document, the equivalent URL-encoded notation would be as follows: *

* id=1 * &name='John+Smith', * &uri=http://sample/addressBook/person/1, * &addressBookUri=http://sample/addressBook, * &birthDate=1946-08-12T00:00:00Z, * &otherIds=null, * &addresses=@( * ( * uri=http://sample/addressBook/address/1, * personUri=http://sample/addressBook/person/1, * id=1, * street='100+Main+Street', * city=Anywhereville, * state=NY, * zip=12345, * isCurrent=true * ) * ) *

* *
Example:
*

* // Serialize a Map * Map m = new ObjectMap("{a:'b',c:1,d:false,e:['f',1,false],g:{h:'i'}}"); * * // Serialize to value equivalent to JSON. * // Produces "a=b&c=1&d=false&e=@(f,1,false)&g=(h=i)" * String s = UrlEncodingSerializer.DEFAULT.serialize(s); * * // Serialize a bean * public class Person { * public Person(String s); * public String getName(); * public int getAge(); * public Address getAddress(); * public boolean deceased; * } * * public class Address { * public String getStreet(); * public String getCity(); * public String getState(); * public int getZip(); * } * * Person p = new Person("John Doe", 23, "123 Main St", "Anywhere", "NY", 12345, false); * * // Produces "name=John+Doe&age=23&address=(street='123+Main+St',city=Anywhere,state=NY,zip=12345)&deceased=false" * String s = UrlEncodingSerializer.DEFAULT.serialize(s); *

*/ public class UrlEncodingSerializer extends UonSerializer implements PartSerializer { //------------------------------------------------------------------------------------------------------------------- // Configurable properties //------------------------------------------------------------------------------------------------------------------- private static final String PREFIX = "UrlEncodingSerializer."; /** * Serialize bean property collections/arrays as separate key/value pairs ({@link Boolean}, default=false). * *

* If false, serializing the array [1,2,3] results in ?key=$a(1,2,3). * If true, serializing the same array results in ?key=1&key=2&key=3. * *

* Example: *

* public class A { * public String[] f1 = {"a","b"}; * public List<String> f2 = new LinkedList<String>(Arrays.asList(new String[]{"c","d"})); * } * * UrlEncodingSerializer s1 = UrlEncodingSerializer.DEFAULT; * UrlEncodingSerializer s2 = new UrlEncodingSerializerBuilder().expandedParams(true).build(); * * String ss1 = s1.serialize(new A()); // Produces "f1=(a,b)&f2=(c,d)" * String ss2 = s2.serialize(new A()); // Produces "f1=a&f1=b&f2=c&f2=d" *

* *

* This option only applies to beans. * *

Notes:
*
    *
  • If parsing multi-part parameters, it's highly recommended to use Collections or Lists * as bean property types instead of arrays since arrays have to be recreated from scratch every time a value * is added to it. *
*/ public static final String URLENC_expandedParams = PREFIX + "expandedParams"; //------------------------------------------------------------------------------------------------------------------- // Predefined instances //------------------------------------------------------------------------------------------------------------------- /** Reusable instance of {@link UrlEncodingSerializer}, all default settings. */ public static final UrlEncodingSerializer DEFAULT = new UrlEncodingSerializer(PropertyStore.create()); /** Reusable instance of {@link UrlEncodingSerializer.PlainText}. */ public static final UrlEncodingSerializer DEFAULT_PLAINTEXT = new PlainText(PropertyStore.create()); /** Reusable instance of {@link UrlEncodingSerializer.Expanded}. */ public static final UrlEncodingSerializer DEFAULT_EXPANDED = new Expanded(PropertyStore.create()); /** Reusable instance of {@link UrlEncodingSerializer.Readable}. */ public static final UrlEncodingSerializer DEFAULT_READABLE = new Readable(PropertyStore.create()); //------------------------------------------------------------------------------------------------------------------- // Predefined subclasses //------------------------------------------------------------------------------------------------------------------- /** * Equivalent to new UrlEncodingSerializerBuilder().expandedParams(true).build();. */ public static class Expanded extends UrlEncodingSerializer { /** * Constructor. * * @param propertyStore The property store containing all the settings for this object. */ public Expanded(PropertyStore propertyStore) { super(propertyStore.copy().append(URLENC_expandedParams, true)); } } /** * Equivalent to new UrlEncodingSerializerBuilder().useWhitespace(true).build();. */ public static class Readable extends UrlEncodingSerializer { /** * Constructor. * * @param propertyStore The property store containing all the settings for this object. */ public Readable(PropertyStore propertyStore) { super(propertyStore.copy().append(SERIALIZER_useWhitespace, true)); } } /** * Equivalent to new UrlEncodingSerializerBuilder().plainTextParts().build();. */ public static class PlainText extends UrlEncodingSerializer { /** * Constructor. * * @param propertyStore The property store containing all the settings for this object. */ public PlainText(PropertyStore propertyStore) { super(propertyStore.copy().append(UON_paramFormat, "PLAINTEXT")); } } //------------------------------------------------------------------------------------------------------------------- // Instance //------------------------------------------------------------------------------------------------------------------- private final UrlEncodingSerializerContext ctx; /** * Constructor. * * @param propertyStore * The property store containing all the settings for this object. */ public UrlEncodingSerializer(PropertyStore propertyStore) { this(propertyStore, "application/x-www-form-urlencoded"); } /** * Constructor. * * @param propertyStore * The property store containing all the settings for this object. * @param produces * The media type that this serializer produces. * @param accept * The accept media types that the serializer can handle. *

* Can contain meta-characters per the media-type specification of * RFC2616/14.1 *

* If empty, then assumes the only media type supported is produces. *

* For example, if this serializer produces "application/json" but should handle media types of * "application/json" and "text/json", then the arguments should be: *
super(propertyStore, "application/json", "application/json", "text/json"); *
...or... *
super(propertyStore, "application/json", "*​/json"); */ public UrlEncodingSerializer(PropertyStore propertyStore, String produces, String...accept) { super(propertyStore.copy().append(UON_encodeChars, true), produces, accept); this.ctx = createContext(UrlEncodingSerializerContext.class); } @Override /* CoreObject */ public UrlEncodingSerializerBuilder builder() { return new UrlEncodingSerializerBuilder(propertyStore); } //-------------------------------------------------------------------------------- // Methods for constructing individual parameter values. //-------------------------------------------------------------------------------- /** * Converts the specified object to a string using this serializers {@link BeanSession#convertToType(Object, Class)} * method and runs {@link URLEncoder#encode(String,String)} against the results. * *

* Useful for constructing URL parts. * * @param o The object to serialize. * @param urlEncode * URL-encode the string if necessary. * If null, then uses the value of the {@link UonSerializerContext#UON_encodeChars} setting. * @param plainTextParams * Whether we're using plain-text params. * If null, then uses the value from the {@link UrlEncodingSerializerContext#URLENC_paramFormat} setting. * @return The serialized object. */ private String serializePart(Object o, Boolean urlEncode, Boolean plainTextParams) { try { // Shortcut for simple types. ClassMeta cm = getBeanContext().getClassMetaForObject(o); if (cm != null) { if (cm.isNumber() || cm.isBoolean()) return o.toString(); if (cm.isCharSequence()) { String s = o.toString(); boolean ptt = (plainTextParams != null ? plainTextParams : ctx.getParamFormat() == ParamFormat.PLAINTEXT); if (ptt || s.isEmpty() || ! UonUtils.needsQuotes(s)) return (urlEncode ? urlEncode(s) : s); } } StringWriter w = new StringWriter(); UonSerializerSession s = new UonSerializerSession(ctx, urlEncode, createDefaultSessionArgs()); s.serialize(w, o); return w.toString(); } catch (Exception e) { throw new RuntimeException(e); } } //-------------------------------------------------------------------------------- // Entry point methods //-------------------------------------------------------------------------------- @Override /* Serializer */ public WriterSerializerSession createSession(SerializerSessionArgs args) { return new UrlEncodingSerializerSession(ctx, null, args); } @Override /* PartSerializer */ public String serialize(PartType type, Object value) { switch(type) { case HEADER: return serializePart(value, false, true); case FORM_DATA: return serializePart(value, false, null); case PATH: return serializePart(value, false, null); case QUERY: return serializePart(value, false, null); default: return toString(value); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy