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.csv; 014 015import static org.apache.juneau.internal.CollectionUtils.*; 016 017import java.io.*; 018import java.lang.reflect.*; 019import java.nio.charset.*; 020import java.util.*; 021import java.util.function.*; 022import org.apache.juneau.*; 023import org.apache.juneau.httppart.*; 024import org.apache.juneau.internal.*; 025import org.apache.juneau.serializer.*; 026import org.apache.juneau.svl.*; 027 028/** 029 * Session object that lives for the duration of a single use of {@link CsvSerializer}. 030 * 031 * <h5 class='section'>Notes:</h5><ul> 032 * <li class='warn'>This class is not thread safe and is typically discarded after one use. 033 * </ul> 034 * 035 * <h5 class='section'>See Also:</h5><ul> 036 037 * </ul> 038 */ 039public final class CsvSerializerSession extends WriterSerializerSession { 040 041 //----------------------------------------------------------------------------------------------------------------- 042 // Static 043 //----------------------------------------------------------------------------------------------------------------- 044 045 /** 046 * Creates a new builder for this object. 047 * 048 * @param ctx The context creating this session. 049 * @return A new builder. 050 */ 051 public static Builder create(CsvSerializer ctx) { 052 return new Builder(ctx); 053 } 054 055 //----------------------------------------------------------------------------------------------------------------- 056 // Builder 057 //----------------------------------------------------------------------------------------------------------------- 058 059 /** 060 * Builder class. 061 */ 062 @FluentSetters 063 public static class Builder extends WriterSerializerSession.Builder { 064 065 CsvSerializer ctx; 066 067 /** 068 * Constructor 069 * 070 * @param ctx The context creating this session. 071 */ 072 protected Builder(CsvSerializer ctx) { 073 super(ctx); 074 this.ctx = ctx; 075 } 076 077 @Override 078 public CsvSerializerSession build() { 079 return new CsvSerializerSession(this); 080 } 081 082 // <FluentSetters> 083 084 @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */ 085 public <T> Builder apply(Class<T> type, Consumer<T> apply) { 086 super.apply(type, apply); 087 return this; 088 } 089 090 @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */ 091 public Builder debug(Boolean value) { 092 super.debug(value); 093 return this; 094 } 095 096 @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */ 097 public Builder properties(Map<String,Object> value) { 098 super.properties(value); 099 return this; 100 } 101 102 @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */ 103 public Builder property(String key, Object value) { 104 super.property(key, value); 105 return this; 106 } 107 108 @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */ 109 public Builder unmodifiable() { 110 super.unmodifiable(); 111 return this; 112 } 113 114 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 115 public Builder locale(Locale value) { 116 super.locale(value); 117 return this; 118 } 119 120 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 121 public Builder localeDefault(Locale value) { 122 super.localeDefault(value); 123 return this; 124 } 125 126 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 127 public Builder mediaType(MediaType value) { 128 super.mediaType(value); 129 return this; 130 } 131 132 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 133 public Builder mediaTypeDefault(MediaType value) { 134 super.mediaTypeDefault(value); 135 return this; 136 } 137 138 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 139 public Builder timeZone(TimeZone value) { 140 super.timeZone(value); 141 return this; 142 } 143 144 @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */ 145 public Builder timeZoneDefault(TimeZone value) { 146 super.timeZoneDefault(value); 147 return this; 148 } 149 150 @Override /* GENERATED - org.apache.juneau.serializer.SerializerSession.Builder */ 151 public Builder javaMethod(Method value) { 152 super.javaMethod(value); 153 return this; 154 } 155 156 @Override /* GENERATED - org.apache.juneau.serializer.SerializerSession.Builder */ 157 public Builder resolver(VarResolverSession value) { 158 super.resolver(value); 159 return this; 160 } 161 162 @Override /* GENERATED - org.apache.juneau.serializer.SerializerSession.Builder */ 163 public Builder schema(HttpPartSchema value) { 164 super.schema(value); 165 return this; 166 } 167 168 @Override /* GENERATED - org.apache.juneau.serializer.SerializerSession.Builder */ 169 public Builder schemaDefault(HttpPartSchema value) { 170 super.schemaDefault(value); 171 return this; 172 } 173 174 @Override /* GENERATED - org.apache.juneau.serializer.SerializerSession.Builder */ 175 public Builder uriContext(UriContext value) { 176 super.uriContext(value); 177 return this; 178 } 179 180 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializerSession.Builder */ 181 public Builder fileCharset(Charset value) { 182 super.fileCharset(value); 183 return this; 184 } 185 186 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializerSession.Builder */ 187 public Builder streamCharset(Charset value) { 188 super.streamCharset(value); 189 return this; 190 } 191 192 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializerSession.Builder */ 193 public Builder useWhitespace(Boolean value) { 194 super.useWhitespace(value); 195 return this; 196 } 197 198 // </FluentSetters> 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 final 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 (l.size() > 0) { 231 ClassMeta<?> entryType = getClassMetaForObject(l.iterator().next()); 232 if (entryType.isBean()) { 233 BeanMeta<?> bm = entryType.getBeanMeta(); 234 Flag addComma = Flag.create(); 235 bm.forEachProperty(x -> x.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(y -> y.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 final 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}