001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.msgpack; 014 015import java.util.*; 016import java.util.concurrent.*; 017 018import org.apache.juneau.*; 019import org.apache.juneau.annotation.*; 020import org.apache.juneau.serializer.*; 021 022/** 023 * Serializes POJO models to MessagePack. 024 * 025 * <h5 class='section'>Media types:</h5> 026 * 027 * Handles <c>Accept</c> types: <bc>octal/msgpack</bc> 028 * <p> 029 * Produces <c>Content-Type</c> types: <bc>octal/msgpack</bc> 030 */ 031@ConfigurableContext 032public class MsgPackSerializer extends OutputStreamSerializer implements MsgPackMetaProvider, MsgPackCommon { 033 034 //------------------------------------------------------------------------------------------------------------------- 035 // Configurable properties 036 //------------------------------------------------------------------------------------------------------------------- 037 038 static final String PREFIX = "MsgPackSerializer"; 039 040 /** 041 * Configuration property: Add <js>"_type"</js> properties when needed. 042 * 043 * <h5 class='section'>Property:</h5> 044 * <ul class='spaced-list'> 045 * <li><b>ID:</b> {@link org.apache.juneau.msgpack.MsgPackSerializer#MSGPACK_addBeanTypes MSGPACK_addBeanTypes} 046 * <li><b>Name:</b> <js>"MsgPackSerializer.addBeanTypes.b"</js> 047 * <li><b>Data type:</b> <jk>boolean</jk> 048 * <li><b>System property:</b> <c>MsgPackSerializer.addBeanTypes</c> 049 * <li><b>Environment variable:</b> <c>MSGPACKSERIALIZER_ADDBEANTYPES</c> 050 * <li><b>Default:</b> <jk>false</jk> 051 * <li><b>Session property:</b> <jk>false</jk> 052 * <li><b>Annotations:</b> 053 * <ul> 054 * <li class='ja'>{@link org.apache.juneau.msgpack.annotation.MsgPackConfig#addBeanTypes()} 055 * </ul> 056 * <li><b>Methods:</b> 057 * <ul> 058 * <li class='jm'>{@link org.apache.juneau.msgpack.MsgPackSerializerBuilder#addBeanTypes(boolean)} 059 * </ul> 060 * </ul> 061 * 062 * <h5 class='section'>Description:</h5> 063 * <p> 064 * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred 065 * through reflection. 066 * 067 * <p> 068 * When present, this value overrides the {@link #SERIALIZER_addBeanTypes} setting and is 069 * provided to customize the behavior of specific serializers in a {@link SerializerGroup}. 070 */ 071 public static final String MSGPACK_addBeanTypes = PREFIX + ".addBeanTypes.b"; 072 073 074 //------------------------------------------------------------------------------------------------------------------- 075 // Predefined instances 076 //------------------------------------------------------------------------------------------------------------------- 077 078 /** Default serializer, all default settings.*/ 079 public static final MsgPackSerializer DEFAULT = new MsgPackSerializer(PropertyStore.DEFAULT); 080 081 /** Default serializer, all default settings, spaced-hex string output.*/ 082 public static final MsgPackSerializer DEFAULT_SPACED_HEX = new SpacedHex(PropertyStore.DEFAULT); 083 084 /** Default serializer, all default settings, spaced-hex string output.*/ 085 public static final MsgPackSerializer DEFAULT_BASE64 = new Base64(PropertyStore.DEFAULT); 086 087 //------------------------------------------------------------------------------------------------------------------- 088 // Predefined subclasses 089 //------------------------------------------------------------------------------------------------------------------- 090 091 /** Default serializer, spaced-hex string output. */ 092 public static class SpacedHex extends MsgPackSerializer { 093 094 /** 095 * Constructor. 096 * 097 * @param ps The property store containing all the settings for this object. 098 */ 099 public SpacedHex(PropertyStore ps) { 100 super( 101 ps.builder().set(OSSERIALIZER_binaryFormat, BinaryFormat.SPACED_HEX).build() 102 ); 103 } 104 } 105 106 /** Default serializer, BASE64 string output. */ 107 public static class Base64 extends MsgPackSerializer { 108 109 /** 110 * Constructor. 111 * 112 * @param ps The property store containing all the settings for this object. 113 */ 114 public Base64(PropertyStore ps) { 115 super( 116 ps.builder().set(OSSERIALIZER_binaryFormat, BinaryFormat.BASE64).build() 117 ); 118 } 119 } 120 121 //------------------------------------------------------------------------------------------------------------------- 122 // Instance 123 //------------------------------------------------------------------------------------------------------------------- 124 125 private final boolean 126 addBeanTypes; 127 private final Map<ClassMeta<?>,MsgPackClassMeta> msgPackClassMetas = new ConcurrentHashMap<>(); 128 private final Map<BeanPropertyMeta,MsgPackBeanPropertyMeta> msgPackBeanPropertyMetas = new ConcurrentHashMap<>(); 129 130 /** 131 * Constructor. 132 * 133 * @param ps The property store containing all the settings for this object. 134 */ 135 public MsgPackSerializer(PropertyStore ps) { 136 super(ps, "octal/msgpack", null); 137 this.addBeanTypes = getBooleanProperty(MSGPACK_addBeanTypes, getBooleanProperty(SERIALIZER_addBeanTypes, false)); 138 } 139 140 @Override /* Context */ 141 public MsgPackSerializerBuilder builder() { 142 return new MsgPackSerializerBuilder(getPropertyStore()); 143 } 144 145 /** 146 * Instantiates a new clean-slate {@link MsgPackSerializerBuilder} object. 147 * 148 * <p> 149 * This is equivalent to simply calling <code><jk>new</jk> MsgPackSerializerBuilder()</code>. 150 * 151 * <p> 152 * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies 153 * the settings of the object called on. 154 * 155 * @return A new {@link MsgPackSerializerBuilder} object. 156 */ 157 public static MsgPackSerializerBuilder create() { 158 return new MsgPackSerializerBuilder(); 159 } 160 161 @Override /* Context */ 162 public MsgPackSerializerSession createSession() { 163 return createSession(createDefaultSessionArgs()); 164 } 165 166 @Override /* Serializer */ 167 public MsgPackSerializerSession createSession(SerializerSessionArgs args) { 168 return new MsgPackSerializerSession(this, args); 169 } 170 171 //----------------------------------------------------------------------------------------------------------------- 172 // Extended metadata 173 //----------------------------------------------------------------------------------------------------------------- 174 175 @Override /* MsgPackMetaProvider */ 176 public MsgPackClassMeta getMsgPackClassMeta(ClassMeta<?> cm) { 177 MsgPackClassMeta m = msgPackClassMetas.get(cm); 178 if (m == null) { 179 m = new MsgPackClassMeta(cm, this); 180 msgPackClassMetas.put(cm, m); 181 } 182 return m; 183 } 184 185 @Override /* MsgPackMetaProvider */ 186 public MsgPackBeanPropertyMeta getMsgPackBeanPropertyMeta(BeanPropertyMeta bpm) { 187 if (bpm == null) 188 return MsgPackBeanPropertyMeta.DEFAULT; 189 MsgPackBeanPropertyMeta m = msgPackBeanPropertyMetas.get(bpm); 190 if (m == null) { 191 m = new MsgPackBeanPropertyMeta(bpm.getDelegateFor(), this); 192 msgPackBeanPropertyMetas.put(bpm, m); 193 } 194 return m; 195 } 196 197 //----------------------------------------------------------------------------------------------------------------- 198 // Properties 199 //----------------------------------------------------------------------------------------------------------------- 200 201 @Override 202 protected final boolean isAddBeanTypes() { 203 return addBeanTypes; 204 } 205 206 //----------------------------------------------------------------------------------------------------------------- 207 // Other methods 208 //----------------------------------------------------------------------------------------------------------------- 209 210 @Override /* Context */ 211 public ObjectMap toMap() { 212 return super.toMap() 213 .append("MsgPackSerializer", new DefaultFilteringObjectMap() 214 .append("addBeanTypes", addBeanTypes) 215 ); 216 } 217}