com.github.heuermh.personalgenome.client.converter.JacksonPersonalGenomeConverter.java Source code

Java tutorial

Introduction

Here is the source code for com.github.heuermh.personalgenome.client.converter.JacksonPersonalGenomeConverter.java

Source

/*
    
personal-genome-client  Java client for the 23andMe Personal Genome API.
Copyright (c) 2012-2013 held jointly by the individual authors.
    
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or (at
your option) any later version.
    
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
License for more details.
    
You should have received a copy of the GNU Lesser General Public License
along with this library;  if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
    
> http://www.fsf.org/licensing/licenses/lgpl.html
> http://www.opensource.org/licenses/lgpl-license.php
    
*/
package com.github.heuermh.personalgenome.client.converter;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.InputStream;
import java.io.IOException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

import com.github.heuermh.personalgenome.client.AccessDeniedException;
import com.github.heuermh.personalgenome.client.Ancestry;
import com.github.heuermh.personalgenome.client.Carrier;
import com.github.heuermh.personalgenome.client.DrugResponse;
import com.github.heuermh.personalgenome.client.Genome;
import com.github.heuermh.personalgenome.client.Genotype;
import com.github.heuermh.personalgenome.client.Haplogroup;
import com.github.heuermh.personalgenome.client.InvalidClientException;
import com.github.heuermh.personalgenome.client.InvalidRequestException;
import com.github.heuermh.personalgenome.client.InvalidScopeException;
import com.github.heuermh.personalgenome.client.MaternalTerminalSnp;
import com.github.heuermh.personalgenome.client.PaternalTerminalSnp;
import com.github.heuermh.personalgenome.client.PersonalGenomeClientException;
import com.github.heuermh.personalgenome.client.PersonalGenomeConverter;
import com.github.heuermh.personalgenome.client.Profile;
import com.github.heuermh.personalgenome.client.ProfileName;
import com.github.heuermh.personalgenome.client.Relative;
import com.github.heuermh.personalgenome.client.Relationship;
import com.github.heuermh.personalgenome.client.Risk;
import com.github.heuermh.personalgenome.client.Trait;
import com.github.heuermh.personalgenome.client.User;
import com.github.heuermh.personalgenome.client.UserName;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Converter for <code>application/json</code> mime type implemented using Jackson.
 */
public final class JacksonPersonalGenomeConverter implements PersonalGenomeConverter {
    private final JsonFactory jsonFactory;
    private final Logger logger = LoggerFactory.getLogger(JacksonPersonalGenomeConverter.class);

    //@Inject
    public JacksonPersonalGenomeConverter(final JsonFactory jsonFactory) {
        checkNotNull(jsonFactory);
        this.jsonFactory = jsonFactory;
    }

    @Override
    public PersonalGenomeClientException parseException(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            String error = null;
            String errorDescription = null;
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("error".equals(field)) {
                    error = parser.getText();
                } else if ("error_description".equals(field)) {
                    errorDescription = parser.getText();
                }
            }
            if ("access_denied".equals(error)) {
                return new AccessDeniedException(errorDescription);
            } else if ("invalid_client".equals(error)) {
                return new InvalidClientException(errorDescription);
            } else if ("invalid_request".equals(error)) {
                return new InvalidRequestException(errorDescription);
            } else if ("invalid_scope".equals(error)) {
                return new InvalidScopeException(errorDescription);
            }
            return new PersonalGenomeClientException(errorDescription);
        } catch (IOException e) {
            logger.warn("could not parse exception", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return new PersonalGenomeClientException("unknown error");
    }

    /**
     * Parse the specified input stream and return a user.
     *
     * @param inputStream input stream
     * @return the specified input stream parsed into a user
     */
    @Override
    public User parseUser(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            String id = null;
            String profileId = null;
            boolean genotyped = false;
            List<Profile> profiles = new ArrayList<Profile>();

            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();
                if ("id".equals(field)) {
                    id = parser.getText();
                } else if ("profiles".equals(field)) {
                    while (parser.nextToken() != JsonToken.END_ARRAY) {
                        while (parser.nextToken() != JsonToken.END_OBJECT) {
                            String profileField = parser.getCurrentName();
                            parser.nextToken();
                            if ("id".equals(profileField)) {
                                profileId = parser.getText();
                            } else if ("genotyped".equals(profileField)) {
                                genotyped = parser.getBooleanValue();
                            }
                        }
                        profiles.add(new Profile(profileId, genotyped));
                    }
                }
            }
            return new User(id, profiles);
        } catch (IOException e) {
            logger.warn("could not parse user", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return null;
    }

    @Override
    public UserName parseNames(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            String id = null;
            String firstName = null;
            String lastName = null;
            String profileId = null;
            String profileFirstName = null;
            String profileLastName = null;
            List<ProfileName> profileNames = new ArrayList<ProfileName>();

            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();
                if ("id".equals(field)) {
                    id = parser.getText();
                } else if ("first_name".equals(field)) {
                    firstName = parser.getText();
                } else if ("last_name".equals(field)) {
                    lastName = parser.getText();
                } else if ("profiles".equals(field)) {
                    while (parser.nextToken() != JsonToken.END_ARRAY) {
                        while (parser.nextToken() != JsonToken.END_OBJECT) {
                            String profileNameField = parser.getCurrentName();
                            parser.nextToken();
                            if ("id".equals(profileNameField)) {
                                profileId = parser.getText();
                            } else if ("first_name".equals(profileNameField)) {
                                profileFirstName = parser.getText();
                            } else if ("last_name".equals(profileNameField)) {
                                profileLastName = parser.getText();
                            }
                        }
                        profileNames.add(new ProfileName(profileId, profileFirstName, profileLastName));
                    }
                }
            }
            return new UserName(id, firstName, lastName, profileNames);
        } catch (IOException e) {
            logger.warn("could not parse names", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return null;
    }

    @Override
    public Haplogroup parseHaplogroups(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            String id = null;
            String maternal = null;
            String paternal = null;
            String rsid = null;
            String rcrsPosition = null;
            String snp = null;
            List<PaternalTerminalSnp> paternalTerminalSnps = new ArrayList<PaternalTerminalSnp>();
            List<MaternalTerminalSnp> maternalTerminalSnps = new ArrayList<MaternalTerminalSnp>();

            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("id".equals(field)) {
                    id = parser.getText();
                } else if ("maternal".equals(field)) {
                    maternal = parser.getText();
                } else if ("paternal".equals(field)) {
                    paternal = "null" == parser.getText() ? null : parser.getText();
                } else if ("maternal_terminal_snps".equals(field)) {
                    while (parser.nextToken() != JsonToken.END_ARRAY) {
                        while (parser.nextToken() != JsonToken.END_OBJECT) {
                            String maternalTerminalSnpsField = parser.getCurrentName();
                            parser.nextToken();

                            if ("rsid".equals(maternalTerminalSnpsField)) {
                                rsid = parser.getText();
                            } else if ("rcrs_position".equals(maternalTerminalSnpsField)) {
                                rcrsPosition = parser.getText();
                            }
                        }
                        maternalTerminalSnps.add(new MaternalTerminalSnp(rsid, rcrsPosition));
                    }
                } else if ("paternal_terminal_snps".equals(field)) {
                    while (parser.nextToken() != JsonToken.END_ARRAY) {
                        while (parser.nextToken() != JsonToken.END_OBJECT) {
                            String paternalTerminalSnpsField = parser.getCurrentName();
                            parser.nextToken();

                            if ("rsid".equals(paternalTerminalSnpsField)) {
                                rsid = parser.getText();
                            } else if ("snp".equals(paternalTerminalSnpsField)) {
                                snp = parser.getText();
                            }
                        }
                        paternalTerminalSnps.add(new PaternalTerminalSnp(rsid, snp));
                    }
                }
            }
            return new Haplogroup(id, paternal, maternal, paternalTerminalSnps, maternalTerminalSnps);
        } catch (IOException e) {
            logger.warn("could not parse haplogroups", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return null;
    }

    @Override
    public Genotype parseGenotypes(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            String id = null;
            String location = null;
            String interpretation = null;
            Map<String, String> values = new HashMap<String, String>();

            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("id".equals(field)) {
                    id = parser.getText();
                } else {
                    location = field;
                    interpretation = parser.getText();
                    values.put(location, interpretation);
                }
            }
            return new Genotype(id, values);
        } catch (IOException e) {
            logger.warn("could not parse genotypes");
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return null;
    }

    @Override
    public Genome parseGenomes(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            String id = null;
            String values = null;
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("id".equals(field)) {
                    id = parser.getText();
                } else if ("genome".equals(field)) {
                    values = parser.getText();
                }
            }
            return new Genome(id, values);
        } catch (IOException e) {
            logger.warn("could not parse genomes", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return null;
    }

    List<Ancestry> parseSubPopulation(final String id, final List<Ancestry> ancestries, final JsonParser parser)
            throws IOException {
        String label = null;
        double proportion = 0.0d;
        double unassigned = 0.0d;
        List<Ancestry> subPopulations = new ArrayList<Ancestry>();
        while (parser.nextToken() != JsonToken.END_ARRAY) {
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("label".equals(field)) {
                    label = parser.getText();
                } else if ("proportion".equals(field)) {
                    proportion = Double.parseDouble(parser.getText());
                } else if ("unassigned".equals(field)) {
                    unassigned = Double.parseDouble(parser.getText());
                } else if ("sub_populations".equals(field)) {
                    subPopulations = parseSubPopulation(id, subPopulations, parser);
                }
            }
            Ancestry ancestry = new Ancestry(id, label, proportion, unassigned, subPopulations);
            ancestries.add(ancestry);
            label = null;
            proportion = 0.0d;
            unassigned = 0.0d;
            subPopulations.clear();
        }
        return ancestries;
    }

    @Override
    public Ancestry parseAncestry(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            String id = null;
            String label = null;
            double proportion = 0.0d;
            double unassigned = 0.0d;
            List<Ancestry> subPopulations = new ArrayList<Ancestry>();
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("id".equals(field)) {
                    id = parser.getText();
                } else if ("ancestry".equals(field)) {
                    while (parser.nextToken() != JsonToken.END_OBJECT) {
                        String ancestryField = parser.getCurrentName();
                        parser.nextToken();

                        if ("label".equals(ancestryField)) {
                            label = parser.getText();
                        } else if ("proportion".equals(ancestryField)) {
                            proportion = Double.parseDouble(parser.getText());
                        } else if ("unassigned".equals(ancestryField)) {
                            unassigned = Double.parseDouble(parser.getText());
                        } else if ("sub_populations".equals(ancestryField)) {
                            subPopulations = parseSubPopulation(id, subPopulations, parser);
                        }
                    }
                }
            }
            return new Ancestry(id, label, proportion, unassigned, subPopulations);
        } catch (IOException e) {
            logger.warn("could not parse ancestry", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return null;
    }

    @Override
    public double parseNeanderthalProportion(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            double proportion = -1d;
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("neanderthal".equals(field)) {
                    while (parser.nextToken() != JsonToken.END_OBJECT) {
                        String neanderthalField = parser.getCurrentName();
                        parser.nextToken();

                        if ("proportion".equals(neanderthalField)) {
                            proportion = Double.parseDouble(parser.getText());
                        }
                    }
                }
            }
            return proportion;
        } catch (IOException e) {
            logger.warn("could not parse neanderthal proportion", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return -1d;
    }

    @Override
    public List<Relative> parseRelatives(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            List<Relative> relatives = new ArrayList<Relative>();

            String profileId = null;
            String matchId = null;
            double similarity = 0.0d;
            int sharedSegments = 0;
            Relationship relationship = null;
            Relationship userRelationship = null;
            Set<Relationship> range = new HashSet<Relationship>();

            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("id".equals(field)) {
                    profileId = parser.getText();
                } else if ("relatives".equals(field)) {
                    while (parser.nextToken() != JsonToken.END_ARRAY) {
                        while (parser.nextToken() != JsonToken.END_OBJECT) {
                            String relativeField = parser.getCurrentName();
                            parser.nextToken();

                            if ("match_id".equals(relativeField)) {
                                matchId = parser.getText();
                            } else if ("similarity".equals(relativeField)) {
                                similarity = Double.parseDouble(parser.getText());
                            } else if ("shared_segments".equals(relativeField)) {
                                sharedSegments = parser.getIntValue();
                            } else if ("relationship".equals(relativeField)) {
                                relationship = Relationship.fromDescription(parser.getText());
                            } else if ("user_relationship_code".equals(relativeField)) {
                                String code = parser.getText();
                                userRelationship = code == "null" ? null
                                        : Relationship.fromCode(Integer.parseInt(code));
                            } else if ("predicted_relationship_code".equals(relativeField)) {
                                if (relationship == null) {
                                    String code = parser.getText();
                                    relationship = code == "null" ? null
                                            : Relationship.fromCode(Integer.parseInt(code));
                                }
                            } else if ("range".equals(relativeField)) {
                                while (parser.nextToken() != JsonToken.END_ARRAY) {
                                    range.add(Relationship.fromDescription(parser.getText()));
                                }
                            }
                            // ignored nested fields
                            else if ("family_locations".equals(relativeField)) {
                                while (parser.nextToken() != JsonToken.END_ARRAY) {
                                    // ignore
                                }
                            } else if ("family_surnames".equals(relativeField)) {
                                while (parser.nextToken() != JsonToken.END_ARRAY) {
                                    // ignore
                                }
                            } else if ("profile_picture_urls".equals(relativeField)) {
                                while (parser.nextToken() != JsonToken.END_OBJECT) {
                                    // ignore
                                }
                            }
                        }
                    }
                    relatives.add(new Relative(profileId, matchId, similarity, sharedSegments, relationship,
                            userRelationship, range));
                    matchId = null;
                    similarity = 0.0d;
                    sharedSegments = 0;
                    relationship = null;
                    userRelationship = null;
                    range.clear();
                }
            }
            return relatives;
        } catch (IOException e) {
            logger.warn("could not parse relatives", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return null;
    }

    @Override
    public List<Risk> parseRisks(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            String id = null;
            String reportId = null;
            String description = null;
            double risk = 0.0d;
            double populationRisk = 0.0d;
            List<Risk> risks = new ArrayList<Risk>();
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("id".equals(field)) {
                    id = parser.getText();
                } else if ("risks".equals(field)) {
                    while (parser.nextToken() != JsonToken.END_ARRAY) {
                        while (parser.nextToken() != JsonToken.END_OBJECT) {
                            String riskField = parser.getCurrentName();
                            parser.nextToken();

                            if ("report_id".equals(riskField)) {
                                reportId = parser.getText();
                            } else if ("description".equals(riskField)) {
                                description = parser.getText();
                            } else if ("risk".equals(riskField)) {
                                risk = Double.parseDouble(parser.getText());
                            } else if ("population_risk".equals(riskField)) {
                                populationRisk = Double.parseDouble(parser.getText());
                            }
                        }
                        risks.add(new Risk(id, reportId, description, risk, populationRisk));
                        reportId = null;
                        description = null;
                        risk = 0.0d;
                        populationRisk = 0.0d;
                    }
                }
            }
            return risks;
        } catch (IOException e) {
            logger.warn("could not parse risks", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return null;
    }

    @Override
    public List<Carrier> parseCarriers(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            String id = null;
            String reportId = null;
            String description = null;
            int mutations = 0;
            List<Carrier> carriers = new ArrayList<Carrier>();
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("id".equals(field)) {
                    id = parser.getText();
                } else if ("carriers".equals(field)) {
                    while (parser.nextToken() != JsonToken.END_ARRAY) {
                        while (parser.nextToken() != JsonToken.END_OBJECT) {
                            String carrierField = parser.getCurrentName();
                            parser.nextToken();

                            if ("report_id".equals(carrierField)) {
                                reportId = parser.getText();
                            } else if ("description".equals(carrierField)) {
                                description = parser.getText();
                            } else if ("mutations".equals(carrierField)) {
                                mutations = Integer.parseInt(parser.getText());
                            }
                        }
                        carriers.add(new Carrier(id, reportId, description, mutations));
                        reportId = null;
                        description = null;
                        mutations = 0;
                    }
                }
            }
            return carriers;
        } catch (IOException e) {
            logger.warn("could not parse carriers", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return null;
    }

    @Override
    public List<DrugResponse> parseDrugResponses(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            String id = null;
            String reportId = null;
            String description = null;
            String status = null;
            List<DrugResponse> drugResponses = new ArrayList<DrugResponse>();
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("id".equals(field)) {
                    id = parser.getText();
                } else if ("drug_responses".equals(field)) {
                    while (parser.nextToken() != JsonToken.END_ARRAY) {
                        while (parser.nextToken() != JsonToken.END_OBJECT) {
                            String drugResponseField = parser.getCurrentName();
                            parser.nextToken();

                            if ("report_id".equals(drugResponseField)) {
                                reportId = parser.getText();
                            } else if ("description".equals(drugResponseField)) {
                                description = parser.getText();
                            } else if ("status".equals(drugResponseField)) {
                                status = parser.getText();
                            }
                        }
                        drugResponses.add(new DrugResponse(id, reportId, description, status));
                        reportId = null;
                        description = null;
                        status = null;
                    }
                }
            }
            return drugResponses;
        } catch (IOException e) {
            logger.warn("could not parse drug responses", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return null;
    }

    @Override
    public List<Trait> parseTraits(final InputStream inputStream) {
        checkNotNull(inputStream);
        JsonParser parser = null;
        try {
            parser = jsonFactory.createParser(inputStream);
            parser.nextToken();

            String id = null;
            String reportId = null;
            String description = null;
            String trait = null;
            Set<String> possibleTraits = new HashSet<String>();
            List<Trait> traits = new ArrayList<Trait>();
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String field = parser.getCurrentName();
                parser.nextToken();

                if ("id".equals(field)) {
                    id = parser.getText();
                } else if ("traits".equals(field)) {
                    while (parser.nextToken() != JsonToken.END_ARRAY) {
                        while (parser.nextToken() != JsonToken.END_OBJECT) {
                            String traitField = parser.getCurrentName();
                            parser.nextToken();

                            if ("report_id".equals(traitField)) {
                                reportId = parser.getText();
                            } else if ("description".equals(traitField)) {
                                description = parser.getText();
                            } else if ("trait".equals(traitField)) {
                                trait = parser.getText();
                            } else if ("possible_traits".equals(traitField)) {
                                while (parser.nextToken() != JsonToken.END_ARRAY) {
                                    possibleTraits.add(parser.getText());
                                }
                            }
                        }
                        traits.add(new Trait(id, reportId, description, trait, possibleTraits));
                        reportId = null;
                        description = null;
                        trait = null;
                        possibleTraits.clear();
                    }
                }
            }
            return traits;
        } catch (IOException e) {
            logger.warn("could not parse traits", e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                parser.close();
            } catch (Exception e) {
                // ignored
            }
        }
        return null;
    }
}