001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.csv; 018 019import static org.apache.juneau.common.utils.Utils.*; 020 021import java.io.*; 022import java.lang.reflect.*; 023import java.nio.charset.*; 024import java.util.*; 025import java.util.function.*; 026 027import org.apache.juneau.*; 028import org.apache.juneau.common.utils.*; 029import org.apache.juneau.httppart.*; 030import org.apache.juneau.internal.*; 031import org.apache.juneau.serializer.*; 032import org.apache.juneau.svl.*; 033 034/** 035 * Session object that lives for the duration of a single use of {@link CsvSerializer}. 036 * 037 * <h5 class='section'>Notes:</h5><ul> 038 * <li class='warn'>This class is not thread safe and is typically discarded after one use. 039 * </ul> 040 * 041 * <h5 class='section'>See Also:</h5><ul> 042 043 * </ul> 044 */ 045public class CsvSerializerSession extends WriterSerializerSession { 046 047 //----------------------------------------------------------------------------------------------------------------- 048 // Static 049 //----------------------------------------------------------------------------------------------------------------- 050 051 /** 052 * Creates a new builder for this object. 053 * 054 * @param ctx The context creating this session. 055 * @return A new builder. 056 */ 057 public static Builder create(CsvSerializer ctx) { 058 return new Builder(ctx); 059 } 060 061 //----------------------------------------------------------------------------------------------------------------- 062 // Builder 063 //----------------------------------------------------------------------------------------------------------------- 064 065 /** 066 * Builder class. 067 */ 068 public static class Builder extends WriterSerializerSession.Builder { 069 070 CsvSerializer ctx; 071 072 /** 073 * Constructor 074 * 075 * @param ctx The context creating this session. 076 */ 077 protected Builder(CsvSerializer ctx) { 078 super(ctx); 079 this.ctx = ctx; 080 } 081 082 @Override 083 public CsvSerializerSession build() { 084 return new CsvSerializerSession(this); 085 } 086 @Override /* Overridden from Builder */ 087 public <T> Builder apply(Class<T> type, Consumer<T> apply) { 088 super.apply(type, apply); 089 return this; 090 } 091 092 @Override /* Overridden from Builder */ 093 public Builder debug(Boolean value) { 094 super.debug(value); 095 return this; 096 } 097 098 @Override /* Overridden from Builder */ 099 public Builder properties(Map<String,Object> value) { 100 super.properties(value); 101 return this; 102 } 103 104 @Override /* Overridden from Builder */ 105 public Builder property(String key, Object value) { 106 super.property(key, value); 107 return this; 108 } 109 110 @Override /* Overridden from Builder */ 111 public Builder unmodifiable() { 112 super.unmodifiable(); 113 return this; 114 } 115 116 @Override /* Overridden from Builder */ 117 public Builder locale(Locale value) { 118 super.locale(value); 119 return this; 120 } 121 122 @Override /* Overridden from Builder */ 123 public Builder localeDefault(Locale value) { 124 super.localeDefault(value); 125 return this; 126 } 127 128 @Override /* Overridden from Builder */ 129 public Builder mediaType(MediaType value) { 130 super.mediaType(value); 131 return this; 132 } 133 134 @Override /* Overridden from Builder */ 135 public Builder mediaTypeDefault(MediaType value) { 136 super.mediaTypeDefault(value); 137 return this; 138 } 139 140 @Override /* Overridden from Builder */ 141 public Builder timeZone(TimeZone value) { 142 super.timeZone(value); 143 return this; 144 } 145 146 @Override /* Overridden from Builder */ 147 public Builder timeZoneDefault(TimeZone value) { 148 super.timeZoneDefault(value); 149 return this; 150 } 151 152 @Override /* Overridden from Builder */ 153 public Builder javaMethod(Method value) { 154 super.javaMethod(value); 155 return this; 156 } 157 158 @Override /* Overridden from Builder */ 159 public Builder resolver(VarResolverSession value) { 160 super.resolver(value); 161 return this; 162 } 163 164 @Override /* Overridden from Builder */ 165 public Builder schema(HttpPartSchema value) { 166 super.schema(value); 167 return this; 168 } 169 170 @Override /* Overridden from Builder */ 171 public Builder schemaDefault(HttpPartSchema value) { 172 super.schemaDefault(value); 173 return this; 174 } 175 176 @Override /* Overridden from Builder */ 177 public Builder uriContext(UriContext value) { 178 super.uriContext(value); 179 return this; 180 } 181 182 @Override /* Overridden from Builder */ 183 public Builder fileCharset(Charset value) { 184 super.fileCharset(value); 185 return this; 186 } 187 188 @Override /* Overridden from Builder */ 189 public Builder streamCharset(Charset value) { 190 super.streamCharset(value); 191 return this; 192 } 193 194 @Override /* Overridden from Builder */ 195 public Builder useWhitespace(Boolean value) { 196 super.useWhitespace(value); 197 return this; 198 } 199 } 200 201 //----------------------------------------------------------------------------------------------------------------- 202 // Instance 203 //----------------------------------------------------------------------------------------------------------------- 204 205 /** 206 * Constructor. 207 * 208 * @param builder The builder for this object. 209 */ 210 protected CsvSerializerSession(Builder builder) { 211 super(builder); 212 } 213 214 @SuppressWarnings("rawtypes") 215 @Override /* SerializerSession */ 216 protected void doSerialize(SerializerPipe pipe, Object o) throws IOException, SerializeException { 217 218 try (CsvWriter w = getCsvWriter(pipe)) { 219 ClassMeta<?> cm = getClassMetaForObject(o); 220 Collection<?> l = null; 221 if (cm.isArray()) { 222 l = alist((Object[])o); 223 } else if (cm.isCollection()) { 224 l = (Collection<?>)o; 225 } else { 226 l = Collections.singleton(o); 227 } 228 229 // TODO - Doesn't support DynaBeans. 230 if (Utils.isNotEmpty(l)) { 231 ClassMeta<?> entryType = getClassMetaForObject(l.iterator().next()); 232 if (entryType.isBean()) { 233 BeanMeta<?> bm = entryType.getBeanMeta(); 234 Flag addComma = Flag.create(); 235 bm.forEachProperty(BeanPropertyMeta::canRead, x -> { 236 addComma.ifSet(() -> w.w(',')).set(); 237 w.writeEntry(x.getName()); 238 }); 239 w.append('\n'); 240 l.forEach(x -> { 241 Flag addComma2 = Flag.create(); 242 BeanMap<?> bean = toBeanMap(x); 243 bm.forEachProperty(BeanPropertyMeta::canRead, y -> { 244 addComma2.ifSet(() -> w.w(',')).set(); 245 w.writeEntry(y.get(bean, y.getName())); 246 }); 247 w.w('\n'); 248 }); 249 } else if (entryType.isMap()) { 250 Flag addComma = Flag.create(); 251 Map first = (Map)l.iterator().next(); 252 first.keySet().forEach(x -> { 253 addComma.ifSet(() -> w.w(',')).set(); 254 w.writeEntry(x); 255 }); 256 w.append('\n'); 257 l.stream().forEach(x -> { 258 Flag addComma2 = Flag.create(); 259 Map map = (Map)x; 260 map.values().forEach(y -> { 261 addComma2.ifSet(() -> w.w(',')).set(); 262 w.writeEntry(y); 263 }); 264 w.w('\n'); 265 }); 266 } else { 267 w.writeEntry("value"); 268 w.append('\n'); 269 l.stream().forEach(x -> { 270 w.writeEntry(x); 271 w.w('\n'); 272 }); 273 } 274 } 275 } 276 } 277 278 CsvWriter getCsvWriter(SerializerPipe out) { 279 Object output = out.getRawOutput(); 280 if (output instanceof CsvWriter) 281 return (CsvWriter)output; 282 CsvWriter w = new CsvWriter(out.getWriter(), isUseWhitespace(), getMaxIndent(), getQuoteChar(), isTrimStrings(), getUriResolver()); 283 out.setWriter(w); 284 return w; 285 } 286}