Skip to content

mmCIF writer emits no entry identifier: getPdbId() is lost on a write-then-read round trip #1143

Closed

Description

@aalhossary

Summary

AbstractCifFileSupplier writes the PDB identifier only as the name of the data_ block. It emits neither _entry.id nor _struct.entry_id, so the identifier is lost for every consumer that reads it as a data item rather than from the block header.

Two independent consumers are affected:

consumer reads result today
BioJava's own CifStructureConsumerImpl.consumeStruct _struct.entry_id Structure.getPdbId() is null after a write-then-read round trip
Jmol's mmCIF reader _entry.id _M.pdbID is empty for a structure passed via openStringInline(structure.toMMCIF())

Steps to reproduce

Structure s = CifStructureConverter.fromInputStream(
        new GZIPInputStream(...open 4hhb.cif.gz...));
System.out.println(s.getPdbId());                 // 4HHB

String cif = CifStructureConverter.toText(s);
System.out.println(cif.contains("_entry.id"));        // false
System.out.println(cif.contains("_struct.entry_id")); // false

Structure back = CifStructureConverter.fromInputStream(
        new ByteArrayInputStream(cif.getBytes()));
System.out.println(back.getPdbId());              // null   <-- expected 4HHB

Actual output of the block header and identifier items as written today:

data_4HHB
(no _entry.id, no _struct.entry_id)

Expected

Structure.getPdbId() should survive a toText() / fromInputStream() round trip, and the written file should carry the identifier where mmCIF consumers look for it.

Why both items matter

_entry.id is the canonical place for the identifier and is what Jmol reads. BioJava's own reader (CifStructureConsumerImpl.consumeStruct) only looks at _struct.entry_id. Writing just one of the two leaves the other consumer broken, so both should be written.

Measured with Jmol, loading the identical structure inline with one item added at a time:

as written today (block header only)  ->  _M.pdbID = []
plus  _entry.id         3ALB          ->  _M.pdbID = [3ALB]
plus  _struct.entry_id  3ALB          ->  _M.pdbID = []
plus  both                            ->  _M.pdbID = [3ALB]

A practical consequence downstream: Jmol's isosurface ... eds fetches an electron-density box around the selection, but it needs an entry to ask about. With load =3alb it renders; with the same structure pushed inline via toMMCIF() it renders nothing, purely because the identifier was lost.

Location

biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/AbstractCifFileSupplier.java, in getInternal(...) — the identifier appears only in the enterBlock(...) call.

Version

Reproduced on master (5b29945). The behaviour is long-standing, not a recent regression.

Activity

  1. added 2 commits that reference this issue on Aug 18, 2026
    909df43
    0225df7
  2. added 2 commits that reference this issue on Aug 26, 2026
    beb127f
    e0b7797
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions