001/* 002 * Copyright 2018 Leibniz-Institut für Analytische Wissenschaften – ISAS – e.V.. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package de.isas.mztab2.io; 017 018import com.fasterxml.jackson.core.JsonGenerator; 019import com.fasterxml.jackson.core.JsonGenerator.Feature; 020import com.fasterxml.jackson.dataformat.csv.CsvFactory; 021import com.fasterxml.jackson.dataformat.csv.CsvMapper; 022import com.fasterxml.jackson.dataformat.csv.CsvSchema; 023import de.isas.mztab2.io.formats.AssayFormat; 024import de.isas.mztab2.io.formats.ContactFormat; 025import de.isas.mztab2.io.formats.CvFormat; 026import de.isas.mztab2.io.formats.DatabaseFormat; 027import de.isas.mztab2.io.formats.InstrumentFormat; 028import de.isas.mztab2.io.formats.MetadataFormat; 029import de.isas.mztab2.io.formats.MsRunFormat; 030import de.isas.mztab2.io.formats.ParameterFormat; 031import de.isas.mztab2.io.formats.PublicationFormat; 032import de.isas.mztab2.io.formats.SampleFormat; 033import de.isas.mztab2.io.formats.SampleProcessingFormat; 034import de.isas.mztab2.io.formats.SmallMoleculeEvidenceFormat; 035import de.isas.mztab2.io.formats.SmallMoleculeFeatureFormat; 036import de.isas.mztab2.io.formats.SmallMoleculeSummaryFormat; 037import de.isas.mztab2.io.formats.SoftwareFormat; 038import de.isas.mztab2.io.formats.StudyVariableFormat; 039import de.isas.mztab2.io.formats.UriFormat; 040import de.isas.mztab2.io.serialization.Serializers; 041import de.isas.mztab2.model.Assay; 042import de.isas.mztab2.model.CV; 043import de.isas.mztab2.model.Contact; 044import de.isas.mztab2.model.Database; 045import de.isas.mztab2.model.Instrument; 046import de.isas.mztab2.model.Metadata; 047import de.isas.mztab2.model.MsRun; 048import de.isas.mztab2.model.MzTab; 049import de.isas.mztab2.model.OptColumnMapping; 050import de.isas.mztab2.model.Parameter; 051import de.isas.mztab2.model.Publication; 052import de.isas.mztab2.model.Sample; 053import de.isas.mztab2.model.SampleProcessing; 054import de.isas.mztab2.model.SmallMoleculeEvidence; 055import de.isas.mztab2.model.SmallMoleculeFeature; 056import de.isas.mztab2.model.SmallMoleculeSummary; 057import de.isas.mztab2.model.Software; 058import de.isas.mztab2.model.StudyVariable; 059import de.isas.mztab2.model.Uri; 060import java.util.Collections; 061import java.util.LinkedHashMap; 062import java.util.List; 063import java.util.Map; 064import java.util.Optional; 065import uk.ac.ebi.pride.jmztab2.model.MZTabConstants; 066import uk.ac.ebi.pride.jmztab2.model.SmallMoleculeColumn; 067import uk.ac.ebi.pride.jmztab2.model.SmallMoleculeEvidenceColumn; 068import uk.ac.ebi.pride.jmztab2.model.SmallMoleculeFeatureColumn; 069import uk.ac.ebi.pride.jmztab2.utils.errors.LogicalErrorType; 070import uk.ac.ebi.pride.jmztab2.utils.errors.MZTabError; 071import uk.ac.ebi.pride.jmztab2.utils.errors.MZTabException; 072 073/** 074 * Default mapper and schema definitions for writing of mzTab files using the 075 * Jackson CSV mapper. 076 * 077 * @author nilshoffmann 078 */ 079public class MzTabWriterDefaults { 080 081 /** 082 * Create a default csv mapper instance. 083 * 084 * @return the csv mapper 085 */ 086 public CsvMapper defaultMapper() { 087 CsvFactory factory = new CsvFactory(); 088 factory.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET); 089 CsvMapper mapper = new CsvMapper(factory); 090 mapper.configure(Feature.IGNORE_UNKNOWN, true); 091 return mapper; 092 } 093 094 /** 095 * Create a metadata section csv mapper. This registers mixins for 096 * serialization of all objects that are part of the metadata section. 097 * 098 * @return the metadata section csv mapper. 099 */ 100 public CsvMapper metadataMapper() { 101 CsvMapper mapper = defaultMapper(); 102 mapper.addMixIn(Metadata.class, MetadataFormat.class); 103 mapper.addMixIn(Assay.class, AssayFormat.class); 104 mapper.addMixIn(Contact.class, ContactFormat.class); 105 mapper.addMixIn(Publication.class, PublicationFormat.class); 106 mapper.addMixIn(Instrument.class, InstrumentFormat.class); 107 mapper.addMixIn(Sample.class, SampleFormat.class); 108 mapper.addMixIn(SampleProcessing.class, SampleProcessingFormat.class); 109 mapper.addMixIn(Software.class, SoftwareFormat.class); 110 mapper.addMixIn(StudyVariable.class, StudyVariableFormat.class); 111 mapper.addMixIn(MsRun.class, MsRunFormat.class); 112 mapper.addMixIn(Database.class, DatabaseFormat.class); 113 mapper.addMixIn(Parameter.class, ParameterFormat.class); 114 mapper.addMixIn(CV.class, CvFormat.class); 115 mapper.addMixIn(Uri.class, UriFormat.class); 116 return mapper; 117 } 118 119 /** 120 * Creates the csv schema for the metadata section (column names, value 121 * separators, array element separators, etc.). 122 * 123 * @param mapper the configured csv mapper 124 * @return the metadata csv schema 125 */ 126 public CsvSchema metaDataSchema(CsvMapper mapper) { 127 CsvSchema.Builder builder = mapper.schema(). 128 builder(); 129 return builder.addColumn("PREFIX", 130 CsvSchema.ColumnType.STRING). 131 addColumn("KEY", 132 CsvSchema.ColumnType.STRING). 133 addArrayColumn("VALUES", MZTabConstants.BAR_S). 134 build(). 135 withAllowComments(true). 136 withArrayElementSeparator(MZTabConstants.BAR_S). 137 withNullValue(MZTabConstants.NULL). 138 withUseHeader(false). 139 withoutQuoteChar(). 140 withoutEscapeChar(). 141 withLineSeparator(MZTabConstants.NEW_LINE). 142 withColumnSeparator(MZTabConstants.TAB); 143 } 144 145 /** 146 * Create a small molecule summary section csv mapper. This registers mixins 147 * for serialization of all objects that are part of the small molecule 148 * summary section. 149 * 150 * @return the small molecule summary section csv mapper. 151 */ 152 public CsvMapper smallMoleculeSummaryMapper() { 153 CsvMapper mapper = metadataMapper(); 154 mapper.addMixIn(SmallMoleculeSummary.class, 155 SmallMoleculeSummaryFormat.class); 156 return mapper; 157 } 158 159 /** 160 * Create a small molecule feature section csv mapper. This registers mixins 161 * for serialization of all objects that are part of the small molecule 162 * feature section. 163 * 164 * @return the small molecule feature section csv mapper. 165 */ 166 public CsvMapper smallMoleculeFeatureMapper() { 167 CsvMapper mapper = metadataMapper(); 168 mapper.addMixIn(SmallMoleculeFeature.class, 169 SmallMoleculeFeatureFormat.class); 170 return mapper; 171 } 172 173 /** 174 * Create a small molecule evidence section csv mapper. This registers 175 * mixins for serialization of all objects that are part of the small 176 * molecule evidence section. 177 * 178 * @return the small molecule evidence section csv mapper. 179 */ 180 public CsvMapper smallMoleculeEvidenceMapper() { 181 CsvMapper mapper = metadataMapper(); 182 mapper.addMixIn(SmallMoleculeEvidence.class, 183 SmallMoleculeEvidenceFormat.class); 184 return mapper; 185 } 186 187 /** 188 * Apply the default csv schema to the provided builder. 189 * 190 * @param builder the builder to use for schema configuration 191 * @return the configured csv schema 192 */ 193 public CsvSchema defaultSchemaForBuilder(CsvSchema.Builder builder) { 194 return builder. 195 build(). 196 withAllowComments(true). 197 withArrayElementSeparator(MZTabConstants.BAR_S). 198 withNullValue(MZTabConstants.NULL). 199 withUseHeader(true). 200 withoutQuoteChar(). 201 withoutEscapeChar(). 202 withLineSeparator(MZTabConstants.NEW_LINE). 203 withColumnSeparator(MZTabConstants.TAB); 204 } 205 206 /** 207 * Creates the csv schema (column names and types) for the small molecule summary section. 208 * 209 * @param mapper the csv mapper 210 * @param mzTabFile the mztab object 211 * @return the configured csv schema for the small molecule summary section 212 * @throws MZTabException 213 */ 214 public CsvSchema smallMoleculeSummarySchema(CsvMapper mapper, 215 MzTab mzTabFile) throws MZTabException { 216 CsvSchema.Builder builder = mapper.schema(). 217 builder(); 218 builder.addColumn(SmallMoleculeSummary.HeaderPrefixEnum.SMH.getValue(), 219 CsvSchema.ColumnType.STRING). 220 addColumn(SmallMoleculeColumn.Stable.columnFor( 221 SmallMoleculeColumn.Stable.SML_ID). 222 getHeader(), 223 CsvSchema.ColumnType.STRING). 224 addColumn(SmallMoleculeColumn.Stable.columnFor( 225 SmallMoleculeColumn.Stable.SMF_ID_REFS). 226 getHeader(), 227 CsvSchema.ColumnType.STRING). 228 addColumn(SmallMoleculeColumn.Stable.columnFor( 229 SmallMoleculeColumn.Stable.DATABASE_IDENTIFIER). 230 getHeader(), 231 CsvSchema.ColumnType.STRING). 232 addColumn(SmallMoleculeColumn.Stable.columnFor( 233 SmallMoleculeColumn.Stable.CHEMICAL_FORMULA). 234 getHeader(), 235 CsvSchema.ColumnType.STRING). 236 addColumn(SmallMoleculeColumn.Stable.columnFor( 237 SmallMoleculeColumn.Stable.SMILES). 238 getHeader(), 239 CsvSchema.ColumnType.STRING). 240 addColumn(SmallMoleculeColumn.Stable.columnFor( 241 SmallMoleculeColumn.Stable.INCHI). 242 getHeader(), 243 CsvSchema.ColumnType.STRING). 244 addColumn(SmallMoleculeColumn.Stable.columnFor( 245 SmallMoleculeColumn.Stable.CHEMICAL_NAME). 246 getHeader(), 247 CsvSchema.ColumnType.STRING). 248 addColumn(SmallMoleculeColumn.Stable.columnFor( 249 SmallMoleculeColumn.Stable.URI). 250 getHeader(), 251 CsvSchema.ColumnType.STRING). 252 addColumn(SmallMoleculeColumn.Stable.columnFor( 253 SmallMoleculeColumn.Stable.THEOR_NEUTRAL_MASS). 254 getHeader(), 255 CsvSchema.ColumnType.STRING). 256 addColumn(SmallMoleculeColumn.Stable.columnFor( 257 SmallMoleculeColumn.Stable.ADDUCT_IONS). 258 getHeader(), 259 CsvSchema.ColumnType.STRING). 260 addColumn(SmallMoleculeColumn.Stable.columnFor( 261 SmallMoleculeColumn.Stable.RELIABILITY). 262 getHeader(), 263 CsvSchema.ColumnType.STRING). 264 addColumn(SmallMoleculeColumn.Stable.columnFor( 265 SmallMoleculeColumn.Stable.BEST_ID_CONFIDENCE_MEASURE). 266 getHeader(), CsvSchema.ColumnType.STRING). 267 addColumn(SmallMoleculeColumn.Stable.columnFor( 268 SmallMoleculeColumn.Stable.BEST_ID_CONFIDENCE_VALUE). 269 getHeader(), CsvSchema.ColumnType.NUMBER_OR_STRING); 270 271 Metadata metadata = Optional.ofNullable(mzTabFile.getMetadata()).orElseThrow(() -> new MZTabException(new MZTabError( 272 LogicalErrorType.NoMetadataSection, -1))); 273 274 List<SmallMoleculeSummary> smsList = Optional.ofNullable(mzTabFile.getSmallMoleculeSummary()).orElseThrow(() -> new MZTabException(new MZTabError( 275 LogicalErrorType.NoSmallMoleculeSummarySection, -1))); 276 277 metadata. 278 getAssay(). 279 forEach((assay) 280 -> { 281 builder.addColumn( 282 SmallMoleculeSummary.Properties.abundanceAssay + "[" + assay. 283 getId() + "]", 284 CsvSchema.ColumnType.NUMBER_OR_STRING); 285 }); 286 metadata. 287 getStudyVariable(). 288 forEach((studyVariable) 289 -> { 290 builder.addColumn( 291 SmallMoleculeSummary.Properties.abundanceStudyVariable + "[" + studyVariable. 292 getId() + "]", CsvSchema.ColumnType.NUMBER_OR_STRING); 293 }); 294 metadata. 295 getStudyVariable(). 296 forEach((studyVariable) 297 -> { 298 builder.addColumn( 299 SmallMoleculeSummary.Properties.abundanceVariationStudyVariable + "[" + studyVariable. 300 getId() + "]", 301 CsvSchema.ColumnType.NUMBER_OR_STRING); 302 }); 303 Map<String, OptColumnMapping> optColumns = new LinkedHashMap<>(); 304 smsList. 305 forEach((SmallMoleculeSummary sms) 306 -> { 307 Optional.ofNullable(sms.getOpt()). 308 orElse(Collections.emptyList()). 309 forEach((ocm) 310 -> { 311 optColumns.putIfAbsent(Serializers. 312 printOptColumnMapping(ocm), 313 ocm); 314 }); 315 }); 316 optColumns.keySet(). 317 forEach((key) 318 -> { 319 builder.addColumn(key, CsvSchema.ColumnType.NUMBER_OR_STRING); 320 }); 321 return defaultSchemaForBuilder(builder); 322 } 323 324 /** 325 * Creates the csv schema (column names and types) for the small molecule feature section. 326 * 327 * @param mapper the csv mapper 328 * @param mzTabFile the mztab object 329 * @return the configured csv schema for the small molecule feature section 330 * @throws MZTabException 331 */ 332 public CsvSchema smallMoleculeFeatureSchema(CsvMapper mapper, 333 MzTab mzTabFile) throws MZTabException { 334 CsvSchema.Builder builder = mapper.schema(). 335 builder(); 336 builder.addColumn(SmallMoleculeFeature.HeaderPrefixEnum.SFH.getValue(), 337 CsvSchema.ColumnType.STRING). 338 addColumn(SmallMoleculeFeatureColumn.Stable.columnFor( 339 SmallMoleculeFeatureColumn.Stable.SMF_ID). 340 getHeader(), 341 CsvSchema.ColumnType.STRING). 342 addColumn(SmallMoleculeFeatureColumn.Stable.columnFor( 343 SmallMoleculeFeatureColumn.Stable.SME_ID_REFS). 344 getHeader(), 345 CsvSchema.ColumnType.STRING). 346 addColumn( 347 SmallMoleculeFeatureColumn.Stable.columnFor( 348 SmallMoleculeFeatureColumn.Stable.SME_ID_REF_AMBIGUITY_CODE). 349 getHeader(), CsvSchema.ColumnType.NUMBER_OR_STRING). 350 addColumn(SmallMoleculeFeatureColumn.Stable.columnFor( 351 SmallMoleculeFeatureColumn.Stable.ADDUCT_ION). 352 getHeader(), 353 CsvSchema.ColumnType.STRING). 354 addColumn(SmallMoleculeFeatureColumn.Stable.columnFor( 355 SmallMoleculeFeatureColumn.Stable.ISOTOPOMER). 356 getHeader(), 357 CsvSchema.ColumnType.STRING). 358 addColumn(SmallMoleculeFeatureColumn.Stable.columnFor( 359 SmallMoleculeFeatureColumn.Stable.EXP_MASS_TO_CHARGE). 360 getHeader(), CsvSchema.ColumnType.NUMBER_OR_STRING). 361 addColumn(SmallMoleculeFeatureColumn.Stable.columnFor( 362 SmallMoleculeFeatureColumn.Stable.CHARGE). 363 getHeader(), 364 CsvSchema.ColumnType.NUMBER_OR_STRING). 365 addColumn( 366 SmallMoleculeFeatureColumn.Stable.columnFor( 367 SmallMoleculeFeatureColumn.Stable.RETENTION_TIME_IN_SECONDS). 368 getHeader(), CsvSchema.ColumnType.NUMBER_OR_STRING). 369 addColumn( 370 SmallMoleculeFeatureColumn.Stable.columnFor( 371 SmallMoleculeFeatureColumn.Stable.RETENTION_TIME_IN_SECONDS_START). 372 getHeader(), CsvSchema.ColumnType.NUMBER_OR_STRING). 373 addColumn( 374 SmallMoleculeFeatureColumn.Stable.columnFor( 375 SmallMoleculeFeatureColumn.Stable.RETENTION_TIME_IN_SECONDS_END). 376 getHeader(), CsvSchema.ColumnType.NUMBER_OR_STRING); 377 Metadata metadata = Optional.ofNullable(mzTabFile.getMetadata()).orElseThrow( 378 () -> new MZTabException(new MZTabError( 379 LogicalErrorType.NoMetadataSection, -1))); 380 Optional.ofNullable(metadata. 381 getAssay()). 382 ifPresent((assayList) 383 -> assayList.forEach((assay) 384 -> { 385 builder.addColumn( 386 SmallMoleculeFeature.Properties.abundanceAssay + "[" + assay. 387 getId() + "]", 388 CsvSchema.ColumnType.NUMBER_OR_STRING); 389 }) 390 ); 391 392 Map<String, OptColumnMapping> optColumns = new LinkedHashMap<>(); 393 mzTabFile.getSmallMoleculeFeature(). 394 forEach((SmallMoleculeFeature smf) 395 -> { 396 Optional.ofNullable(smf.getOpt()). 397 orElse(Collections.emptyList()). 398 forEach((ocm) 399 -> { 400 optColumns.putIfAbsent(Serializers. 401 printOptColumnMapping(ocm), 402 ocm); 403 }); 404 }); 405 optColumns.keySet(). 406 forEach((key) 407 -> { 408 builder.addColumn(key, CsvSchema.ColumnType.NUMBER_OR_STRING); 409 }); 410 return defaultSchemaForBuilder(builder); 411 } 412 413 /** 414 * Creates the csv schema (column names and types) for the small molecule feature section. 415 * 416 * @param mapper the csv mapper 417 * @param mzTabFile the mztab object 418 * @return the configured csv schema for the small molecule feature section 419 * @throws MZTabException 420 */ 421 public CsvSchema smallMoleculeEvidenceSchema(CsvMapper mapper, 422 MzTab mzTabFile) throws MZTabException { 423 CsvSchema.Builder builder = mapper.schema(). 424 builder(); 425 builder.addColumn(SmallMoleculeEvidence.HeaderPrefixEnum.SEH.getValue(), 426 CsvSchema.ColumnType.STRING). 427 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 428 SmallMoleculeEvidenceColumn.Stable.SME_ID). 429 getHeader(), 430 CsvSchema.ColumnType.STRING). 431 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 432 SmallMoleculeEvidenceColumn.Stable.EVIDENCE_INPUT_ID). 433 getHeader(), CsvSchema.ColumnType.NUMBER_OR_STRING). 434 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 435 SmallMoleculeEvidenceColumn.Stable.DATABASE_IDENTIFIER). 436 getHeader(), CsvSchema.ColumnType.STRING). 437 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 438 SmallMoleculeEvidenceColumn.Stable.CHEMICAL_FORMULA). 439 getHeader(), CsvSchema.ColumnType.STRING). 440 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 441 SmallMoleculeEvidenceColumn.Stable.SMILES). 442 getHeader(), 443 CsvSchema.ColumnType.STRING). 444 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 445 SmallMoleculeEvidenceColumn.Stable.INCHI). 446 getHeader(), 447 CsvSchema.ColumnType.STRING). 448 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 449 SmallMoleculeEvidenceColumn.Stable.CHEMICAL_NAME). 450 getHeader(), CsvSchema.ColumnType.STRING). 451 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 452 SmallMoleculeEvidenceColumn.Stable.URI). 453 getHeader(), 454 CsvSchema.ColumnType.STRING). 455 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 456 SmallMoleculeEvidenceColumn.Stable.DERIVATIZED_FORM). 457 getHeader(), CsvSchema.ColumnType.STRING). 458 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 459 SmallMoleculeEvidenceColumn.Stable.ADDUCT_ION). 460 getHeader(), 461 CsvSchema.ColumnType.STRING). 462 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 463 SmallMoleculeEvidenceColumn.Stable.EXP_MASS_TO_CHARGE). 464 getHeader(), CsvSchema.ColumnType.NUMBER_OR_STRING). 465 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 466 SmallMoleculeEvidenceColumn.Stable.CHARGE). 467 getHeader(), 468 CsvSchema.ColumnType.NUMBER_OR_STRING). 469 addColumn( 470 SmallMoleculeEvidenceColumn.Stable.columnFor( 471 SmallMoleculeEvidenceColumn.Stable.THEORETICAL_MASS_TO_CHARGE). 472 getHeader(), CsvSchema.ColumnType.NUMBER_OR_STRING). 473 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 474 SmallMoleculeEvidenceColumn.Stable.SPECTRA_REF). 475 getHeader(), 476 CsvSchema.ColumnType.STRING). 477 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 478 SmallMoleculeEvidenceColumn.Stable.IDENTIFICATION_METHOD). 479 getHeader(), CsvSchema.ColumnType.STRING). 480 addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 481 SmallMoleculeEvidenceColumn.Stable.MS_LEVEL). 482 getHeader(), 483 CsvSchema.ColumnType.STRING); 484 Metadata metadata = Optional.ofNullable(mzTabFile.getMetadata()).orElseThrow(() -> 485 new MZTabException(new MZTabError( 486 LogicalErrorType.NoMetadataSection, -1))); 487 Optional.ofNullable(metadata. 488 getIdConfidenceMeasure()). 489 ifPresent((parameterList) 490 -> { 491 parameterList.forEach((param) 492 -> { 493 builder. 494 addColumn( 495 SmallMoleculeEvidence.Properties.idConfidenceMeasure + "[" + param. 496 getId() + "]", 497 CsvSchema.ColumnType.NUMBER_OR_STRING); 498 }); 499 }); 500 builder.addColumn(SmallMoleculeEvidenceColumn.Stable.columnFor( 501 SmallMoleculeEvidenceColumn.Stable.RANK). 502 getHeader(), 503 CsvSchema.ColumnType.NUMBER_OR_STRING); 504 Map<String, OptColumnMapping> optColumns = new LinkedHashMap<>(); 505 mzTabFile.getSmallMoleculeEvidence(). 506 forEach((SmallMoleculeEvidence sme) 507 -> { 508 Optional.ofNullable(sme.getOpt()). 509 orElse(Collections.emptyList()). 510 forEach((ocm) 511 -> { 512 optColumns.putIfAbsent(Serializers. 513 printOptColumnMapping(ocm), 514 ocm); 515 }); 516 }); 517 optColumns.keySet(). 518 forEach((key) 519 -> { 520 builder.addColumn(key, CsvSchema.ColumnType.NUMBER_OR_STRING); 521 }); 522 return defaultSchemaForBuilder(builder); 523 } 524}