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.collections.*; 021import org.apache.juneau.serializer.*; 022 023/** 024 * Serializes POJO models to MessagePack. 025 * 026 * <h5 class='section'>Media types:</h5> 027 * 028 * Handles <c>Accept</c> types: <bc>octal/msgpack</bc> 029 * <p> 030 * Produces <c>Content-Type</c> types: <bc>octal/msgpack</bc> 031 */ 032@ConfigurableContext 033public class MsgPackSerializer extends OutputStreamSerializer implements MsgPackMetaProvider, MsgPackCommon { 034 035 //------------------------------------------------------------------------------------------------------------------- 036 // Configurable properties 037 //------------------------------------------------------------------------------------------------------------------- 038 039 static final String PREFIX = "MsgPackSerializer"; 040 041 /** 042 * Configuration property: Add <js>"_type"</js> properties when needed. 043 * 044 * <h5 class='section'>Property:</h5> 045 * <ul class='spaced-list'> 046 * <li><b>ID:</b> {@link org.apache.juneau.msgpack.MsgPackSerializer#MSGPACK_addBeanTypes MSGPACK_addBeanTypes} 047 * <li><b>Name:</b> <js>"MsgPackSerializer.addBeanTypes.b"</js> 048 * <li><b>Data type:</b> <jk>boolean</jk> 049 * <li><b>System property:</b> <c>MsgPackSerializer.addBeanTypes</c> 050 * <li><b>Environment variable:</b> <c>MSGPACKSERIALIZER_ADDBEANTYPES</c> 051 * <li><b>Default:</b> <jk>false</jk> 052 * <li><b>Session property:</b> <jk>false</jk> 053 * <li><b>Annotations:</b> 054 * <ul> 055 * <li class='ja'>{@link org.apache.juneau.msgpack.annotation.MsgPackConfig#addBeanTypes()} 056 * </ul> 057 * <li><b>Methods:</b> 058 * <ul> 059 * <li class='jm'>{@link org.apache.juneau.msgpack.MsgPackSerializerBuilder#addBeanTypes()} 060 * </ul> 061 * </ul> 062 * 063 * <h5 class='section'>Description:</h5> 064 * <p> 065 * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred 066 * through reflection. 067 * 068 * <p> 069 * When present, this value overrides the {@link #SERIALIZER_addBeanTypes} setting and is 070 * provided to customize the behavior of specific serializers in a {@link SerializerGroup}. 071 */ 072 public static final String MSGPACK_addBeanTypes = PREFIX + ".addBeanTypes.b"; 073 074 075 //------------------------------------------------------------------------------------------------------------------- 076 // Predefined instances 077 //------------------------------------------------------------------------------------------------------------------- 078 079 /** Default serializer, all default settings.*/ 080 public static final MsgPackSerializer DEFAULT = new MsgPackSerializer(PropertyStore.DEFAULT); 081 082 /** Default serializer, all default settings, spaced-hex string output.*/ 083 public static final MsgPackSerializer DEFAULT_SPACED_HEX = new SpacedHex(PropertyStore.DEFAULT); 084 085 /** Default serializer, all default settings, spaced-hex string output.*/ 086 public static final MsgPackSerializer DEFAULT_BASE64 = new Base64(PropertyStore.DEFAULT); 087 088 //------------------------------------------------------------------------------------------------------------------- 089 // Predefined subclasses 090 //------------------------------------------------------------------------------------------------------------------- 091 092 /** Default serializer, spaced-hex string output. */ 093 public static class SpacedHex extends MsgPackSerializer { 094 095 /** 096 * Constructor. 097 * 098 * @param ps The property store containing all the settings for this object. 099 */ 100 public SpacedHex(PropertyStore ps) { 101 super( 102 ps.builder().setDefault(OSSERIALIZER_binaryFormat, BinaryFormat.SPACED_HEX).build() 103 ); 104 } 105 } 106 107 /** Default serializer, BASE64 string output. */ 108 public static class Base64 extends MsgPackSerializer { 109 110 /** 111 * Constructor. 112 * 113 * @param ps The property store containing all the settings for this object. 114 */ 115 public Base64(PropertyStore ps) { 116 super( 117 ps.builder().setDefault(OSSERIALIZER_binaryFormat, BinaryFormat.BASE64).build() 118 ); 119 } 120 } 121 122 //------------------------------------------------------------------------------------------------------------------- 123 // Instance 124 //------------------------------------------------------------------------------------------------------------------- 125 126 private final boolean 127 addBeanTypes; 128 private final Map<ClassMeta<?>,MsgPackClassMeta> msgPackClassMetas = new ConcurrentHashMap<>(); 129 private final Map<BeanPropertyMeta,MsgPackBeanPropertyMeta> msgPackBeanPropertyMetas = new ConcurrentHashMap<>(); 130 131 /** 132 * Constructor. 133 * 134 * @param ps The property store containing all the settings for this object. 135 */ 136 public MsgPackSerializer(PropertyStore ps) { 137 super(ps, "octal/msgpack", null); 138 this.addBeanTypes = getBooleanProperty(MSGPACK_addBeanTypes, getBooleanProperty(SERIALIZER_addBeanTypes, false)); 139 } 140 141 @Override /* Context */ 142 public MsgPackSerializerBuilder builder() { 143 return new MsgPackSerializerBuilder(getPropertyStore()); 144 } 145 146 /** 147 * Instantiates a new clean-slate {@link MsgPackSerializerBuilder} object. 148 * 149 * <p> 150 * This is equivalent to simply calling <code><jk>new</jk> MsgPackSerializerBuilder()</code>. 151 * 152 * <p> 153 * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies 154 * the settings of the object called on. 155 * 156 * @return A new {@link MsgPackSerializerBuilder} object. 157 */ 158 public static MsgPackSerializerBuilder create() { 159 return new MsgPackSerializerBuilder(); 160 } 161 162 @Override /* Context */ 163 public MsgPackSerializerSession createSession() { 164 return createSession(createDefaultSessionArgs()); 165 } 166 167 @Override /* Serializer */ 168 public MsgPackSerializerSession createSession(SerializerSessionArgs args) { 169 return new MsgPackSerializerSession(this, args); 170 } 171 172 //----------------------------------------------------------------------------------------------------------------- 173 // Extended metadata 174 //----------------------------------------------------------------------------------------------------------------- 175 176 @Override /* MsgPackMetaProvider */ 177 public MsgPackClassMeta getMsgPackClassMeta(ClassMeta<?> cm) { 178 MsgPackClassMeta m = msgPackClassMetas.get(cm); 179 if (m == null) { 180 m = new MsgPackClassMeta(cm, this); 181 msgPackClassMetas.put(cm, m); 182 } 183 return m; 184 } 185 186 @Override /* MsgPackMetaProvider */ 187 public MsgPackBeanPropertyMeta getMsgPackBeanPropertyMeta(BeanPropertyMeta bpm) { 188 if (bpm == null) 189 return MsgPackBeanPropertyMeta.DEFAULT; 190 MsgPackBeanPropertyMeta m = msgPackBeanPropertyMetas.get(bpm); 191 if (m == null) { 192 m = new MsgPackBeanPropertyMeta(bpm.getDelegateFor(), this); 193 msgPackBeanPropertyMetas.put(bpm, m); 194 } 195 return m; 196 } 197 198 //----------------------------------------------------------------------------------------------------------------- 199 // Properties 200 //----------------------------------------------------------------------------------------------------------------- 201 202 @Override 203 protected final boolean isAddBeanTypes() { 204 return addBeanTypes; 205 } 206 207 //----------------------------------------------------------------------------------------------------------------- 208 // Other methods 209 //----------------------------------------------------------------------------------------------------------------- 210 211 @Override /* Context */ 212 public OMap toMap() { 213 return super.toMap() 214 .a("MsgPackSerializer", new DefaultFilteringOMap() 215 .a("addBeanTypes", addBeanTypes) 216 ); 217 } 218}