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}