This is an automated email from the ASF dual-hosted git repository.

tballison pushed a commit to branch TIKA-4809-metadata-key-api
in repository https://gitbox.apache.org/repos/asf/tika.git

commit d748701bcd6950455782978baf7f75be43009989
Author: tallison <[email protected]>
AuthorDate: Tue Aug 11 15:36:22 2026 -0400

    TIKA-4809 metadata-key stage 8: remove setAll, promote ClimateForcast 
(+strays), docs reconciliation
---
 .skills/metadata-schema.md                         |  3 ++
 .../ROOT/pages/developers/metadata-keys.adoc       |  9 ++++--
 .../org/apache/tika/metadata/ClimateForcast.java   | 34 ++++++++++++----------
 .../org/apache/tika/metadata/CreativeCommons.java  |  6 ++--
 .../java/org/apache/tika/metadata/Metadata.java    | 18 +-----------
 .../org/apache/tika/metadata/TikaMimeKeys.java     | 28 ------------------
 .../org/apache/tika/metadata/TestMetadata.java     | 31 --------------------
 .../apache/tika/metadata/metadata-key-fields.json  | 18 ++++++++++++
 .../org/apache/tika/metadata/metadata-keys.json    | 18 ++++++++++++
 .../metadata/schema/MetadataNoUnderscoreTest.java  | 12 ++++++--
 .../org/apache/tika/parser/grib/GribParser.java    | 25 +++++++++++-----
 .../apache/tika/parser/netcdf/NetCDFParser.java    | 25 +++++++++++-----
 .../main/java/org/apache/tika/xmp/XMPMetadata.java |  9 +++---
 13 files changed, 116 insertions(+), 120 deletions(-)

diff --git a/.skills/metadata-schema.md b/.skills/metadata-schema.md
index a31c02cc74..88a1351d00 100644
--- a/.skills/metadata-schema.md
+++ b/.skills/metadata-schema.md
@@ -65,6 +65,9 @@ Failures with stale `X-TIKA:`/underscore/`SHA256` keys 
usually mean *regenerate*
 ## Naming conventions (frozen for 4.0, TIKA-4794)
 
 - All keys are `Property` constants — no bare `String` keys 
(`metadata-string-keys.json` retired).
+  Exception: a few deprecated `String` fields (`IPTC.*_WRONG_CASE`,
+  `TikaCoreProperties.EMBEDDED_RESOURCE_TYPE_KEY`) exist only to construct a 
real `Property`'s
+  name and aren't independent keys.
 - Tika-coined prefix is `tk:` (`X-TIKA:` is legacy); kebab-case, no 
underscores.
 - External-standard names verbatim, *including* the standard's prefix: `dc:`, 
`xmp:`, `cp:`, `extended-properties:`.
 - HTTP has no namespace → `Content-Type`, `Content-Encoding`, `Location` stay 
bare (no `http:`).
diff --git a/docs/modules/ROOT/pages/developers/metadata-keys.adoc 
b/docs/modules/ROOT/pages/developers/metadata-keys.adoc
index 71ca570b70..90fd19ed1b 100644
--- a/docs/modules/ROOT/pages/developers/metadata-keys.adoc
+++ b/docs/modules/ROOT/pages/developers/metadata-keys.adoc
@@ -16,9 +16,12 @@
 = Adding a Metadata Key
 
 Every metadata key Tika can emit is a `Property` constant (or, for 
runtime-minted names like scraped
-HTML `<meta>` tags, a `KeyPrefix`) — there are no bare `String` keys. That 
closed/open key
-space is tracked in a generated, build-gated registry, so adding a key 
involves one extra step beyond
-writing the Java.
+HTML `<meta>` tags, a `KeyPrefix`) — there are no bare `String` keys naming a 
population of writable
+metadata. (A handful of `String` constants remain, e.g. `IPTC`'s four 
`*_WRONG_CASE` fields and
+`TikaCoreProperties.EMBEDDED_RESOURCE_TYPE_KEY`; these are deprecated/internal 
building blocks that
+construct a real `Property`'s name — not independent keys — and are excluded 
from the registry's key
+count for that reason.) That closed/open key space is tracked in a generated, 
build-gated registry, so
+adding a key involves one extra step beyond writing the Java.
 
 == Add the constant
 
diff --git 
a/tika-core/src/main/java/org/apache/tika/metadata/ClimateForcast.java 
b/tika-core/src/main/java/org/apache/tika/metadata/ClimateForcast.java
index 9ad1632837..ccffa8c980 100644
--- a/tika-core/src/main/java/org/apache/tika/metadata/ClimateForcast.java
+++ b/tika-core/src/main/java/org/apache/tika/metadata/ClimateForcast.java
@@ -18,38 +18,40 @@ package org.apache.tika.metadata;
 
 /**
  * Met keys from NCAR CCSM files in the <a
- * href="http://cf-pcmdi.llnl.gov/";>Climate Forecast Convention</a>.
+ * href="http://cf-pcmdi.llnl.gov/";>Climate Forecast Convention</a>. Key 
spellings are the
+ * external convention's own attribute names, verbatim (not Tika-coined) — 
some contain
+ * underscores per that convention.
  */
 public interface ClimateForcast {
 
-    String PROGRAM_ID = "prg_ID";
+    Property PROGRAM_ID = Property.externalText("prg_ID");
 
-    String COMMAND_LINE = "cmd_ln";
+    Property COMMAND_LINE = Property.externalText("cmd_ln");
 
-    String HISTORY = "history";
+    Property HISTORY = Property.externalText("history");
 
-    String TABLE_ID = "table_id";
+    Property TABLE_ID = Property.externalText("table_id");
 
-    String INSTITUTION = "institution";
+    Property INSTITUTION = Property.externalText("institution");
 
-    String SOURCE = "source";
+    Property SOURCE = Property.externalText("source");
 
-    String CONTACT = "contact";
+    Property CONTACT = Property.externalText("contact");
 
-    String PROJECT_ID = "project_id";
+    Property PROJECT_ID = Property.externalText("project_id");
 
-    String CONVENTIONS = "Conventions";
+    Property CONVENTIONS = Property.externalText("Conventions");
 
-    String REFERENCES = "references";
+    Property REFERENCES = Property.externalText("references");
 
-    String ACKNOWLEDGEMENT = "acknowledgement";
+    Property ACKNOWLEDGEMENT = Property.externalText("acknowledgement");
 
-    String REALIZATION = "realization";
+    Property REALIZATION = Property.externalText("realization");
 
-    String EXPERIMENT_ID = "experiment_id";
+    Property EXPERIMENT_ID = Property.externalText("experiment_id");
 
-    String COMMENT = "comment";
+    Property COMMENT = Property.externalText("comment");
 
-    String MODEL_NAME_ENGLISH = "model_name_english";
+    Property MODEL_NAME_ENGLISH = Property.externalText("model_name_english");
 
 }
diff --git 
a/tika-core/src/main/java/org/apache/tika/metadata/CreativeCommons.java 
b/tika-core/src/main/java/org/apache/tika/metadata/CreativeCommons.java
index 122a1fc578..2491d5e1a6 100644
--- a/tika-core/src/main/java/org/apache/tika/metadata/CreativeCommons.java
+++ b/tika-core/src/main/java/org/apache/tika/metadata/CreativeCommons.java
@@ -23,10 +23,10 @@ package org.apache.tika.metadata;
  */
 public interface CreativeCommons {
 
-    String LICENSE_URL = "License-Url";
+    Property LICENSE_URL = Property.externalText("License-Url");
 
-    String LICENSE_LOCATION = "License-Location";
+    Property LICENSE_LOCATION = Property.externalText("License-Location");
 
-    String WORK_TYPE = "Work-Type";
+    Property WORK_TYPE = Property.externalText("Work-Type");
 
 }
diff --git a/tika-core/src/main/java/org/apache/tika/metadata/Metadata.java 
b/tika-core/src/main/java/org/apache/tika/metadata/Metadata.java
index 9ea8385850..2a6dd56a1e 100644
--- a/tika-core/src/main/java/org/apache/tika/metadata/Metadata.java
+++ b/tika-core/src/main/java/org/apache/tika/metadata/Metadata.java
@@ -25,13 +25,11 @@ import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
-import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
-import java.util.Properties;
 import java.util.TimeZone;
 
 import org.slf4j.Logger;
@@ -48,7 +46,7 @@ import org.apache.tika.utils.DateUtils;
  */
 public class Metadata
         implements CreativeCommons, Geographic, HttpHeaders, Message, 
ClimateForcast, TIFF,
-        TikaMimeKeys, Serializable {
+        Serializable {
 
     private static final Logger LOG = LoggerFactory.getLogger(Metadata.class);
 
@@ -448,20 +446,6 @@ public class Metadata
         }
     }
 
-    /**
-     * Copy All key-value pairs from properties.
-     *
-     * @param properties properties to copy from
-     */
-    @SuppressWarnings("unchecked")
-    public void setAll(Properties properties) {
-        Enumeration<String> names = (Enumeration<String>) 
properties.propertyNames();
-        while (names.hasMoreElements()) {
-            String name = names.nextElement();
-            metadata.put(name, new String[]{properties.getProperty(name)});
-        }
-    }
-
     /**
      * Set metadata name/value. Associate the specified value to the specified
      * metadata name. If some previous values were associated to this name,
diff --git a/tika-core/src/main/java/org/apache/tika/metadata/TikaMimeKeys.java 
b/tika-core/src/main/java/org/apache/tika/metadata/TikaMimeKeys.java
deleted file mode 100644
index 7ae685e05e..0000000000
--- a/tika-core/src/main/java/org/apache/tika/metadata/TikaMimeKeys.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.metadata;
-
-/**
- * A collection of Tika metadata keys used in Mime Type resolution
- */
-public interface TikaMimeKeys {
-
-    String TIKA_MIME_FILE = "tika.mime.file";
-
-    String MIME_TYPE_MAGIC = "mime.type.magic";
-
-}
diff --git a/tika-core/src/test/java/org/apache/tika/metadata/TestMetadata.java 
b/tika-core/src/test/java/org/apache/tika/metadata/TestMetadata.java
index 2ce1b8b6c6..e92fe4c3f0 100644
--- a/tika-core/src/test/java/org/apache/tika/metadata/TestMetadata.java
+++ b/tika-core/src/test/java/org/apache/tika/metadata/TestMetadata.java
@@ -27,7 +27,6 @@ import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Locale;
-import java.util.Properties;
 import java.util.Random;
 import java.util.TimeZone;
 import java.util.concurrent.Callable;
@@ -120,36 +119,6 @@ public class TestMetadata extends TikaTest {
         assertEquals("new value 2", values[1]);
     }
 
-    /**
-     * Test for <code>setAll(Properties)</code> method.
-     */
-    @Test
-    public void testSetProperties() {
-        String[] values = null;
-        Metadata meta = new Metadata();
-        Properties props = new Properties();
-
-        meta.setAll(props);
-        assertEquals(0, meta.size());
-
-        props.setProperty("name-one", "value1.1");
-        meta.setAll(props);
-        assertEquals(1, meta.size());
-        values = meta.getValues("name-one");
-        assertEquals(1, values.length);
-        assertEquals("value1.1", values[0]);
-
-        props.setProperty("name-two", "value2.1");
-        meta.setAll(props);
-        assertEquals(2, meta.size());
-        values = meta.getValues("name-one");
-        assertEquals(1, values.length);
-        assertEquals("value1.1", values[0]);
-        values = meta.getValues("name-two");
-        assertEquals(1, values.length);
-        assertEquals("value2.1", values[0]);
-    }
-
     /**
      * Test for <code>get(String)</code> method.
      */
diff --git 
a/tika-metadata-schema/src/main/resources/org/apache/tika/metadata/metadata-key-fields.json
 
b/tika-metadata-schema/src/main/resources/org/apache/tika/metadata/metadata-key-fields.json
index 94488c9af7..a778b9909b 100644
--- 
a/tika-metadata-schema/src/main/resources/org/apache/tika/metadata/metadata-key-fields.json
+++ 
b/tika-metadata-schema/src/main/resources/org/apache/tika/metadata/metadata-key-fields.json
@@ -17,6 +17,24 @@
   
{"class":"org.apache.tika.metadata.Audio","field":"RAW_DISC_NUMBER","key":"audio:raw-disc-number"},
   
{"class":"org.apache.tika.metadata.Audio","field":"RAW_TRACK_NUMBER","key":"audio:raw-track-number"},
   
{"class":"org.apache.tika.metadata.Audio","field":"TRACK_COUNT","key":"audio:track-count"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"ACKNOWLEDGEMENT","key":"acknowledgement"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"COMMAND_LINE","key":"cmd_ln"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"COMMENT","key":"comment"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"CONTACT","key":"contact"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"CONVENTIONS","key":"Conventions"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"EXPERIMENT_ID","key":"experiment_id"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"HISTORY","key":"history"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"INSTITUTION","key":"institution"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"MODEL_NAME_ENGLISH","key":"model_name_english"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"PROGRAM_ID","key":"prg_ID"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"PROJECT_ID","key":"project_id"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"REALIZATION","key":"realization"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"REFERENCES","key":"references"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"SOURCE","key":"source"},
+  
{"class":"org.apache.tika.metadata.ClimateForcast","field":"TABLE_ID","key":"table_id"},
+  
{"class":"org.apache.tika.metadata.CreativeCommons","field":"LICENSE_LOCATION","key":"License-Location"},
+  
{"class":"org.apache.tika.metadata.CreativeCommons","field":"LICENSE_URL","key":"License-Url"},
+  
{"class":"org.apache.tika.metadata.CreativeCommons","field":"WORK_TYPE","key":"Work-Type"},
   
{"class":"org.apache.tika.metadata.DWG","field":"APPLICATION_COMMENT","key":"dwg:application-comment"},
   
{"class":"org.apache.tika.metadata.DWG","field":"APPLICATION_NAME","key":"dwg:application-name"},
   
{"class":"org.apache.tika.metadata.DWG","field":"APPLICATION_VERSION","key":"dwg:application-version"},
diff --git 
a/tika-metadata-schema/src/main/resources/org/apache/tika/metadata/metadata-keys.json
 
b/tika-metadata-schema/src/main/resources/org/apache/tika/metadata/metadata-keys.json
index f601ddfc8f..4297dd26ef 100644
--- 
a/tika-metadata-schema/src/main/resources/org/apache/tika/metadata/metadata-keys.json
+++ 
b/tika-metadata-schema/src/main/resources/org/apache/tika/metadata/metadata-keys.json
@@ -13,6 +13,7 @@
   
{"key":"Content-Location","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"Content-MD5","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"Content-Type","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
+  
{"key":"Conventions","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"Iptc4xmpCore:CiAdrCity","namespace":"Iptc4xmpCore","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"Iptc4xmpCore:CiAdrCtry","namespace":"Iptc4xmpCore","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"Iptc4xmpCore:CiAdrExtadr","namespace":"Iptc4xmpCore","valueType":"TEXT","cardinality":"BAG"},
@@ -64,7 +65,10 @@
   
{"key":"Iptc4xmpExt:RegItemId","namespace":"Iptc4xmpExt","valueType":"TEXT","cardinality":"BAG"},
   
{"key":"Iptc4xmpExt:RegOrgId","namespace":"Iptc4xmpExt","valueType":"TEXT","cardinality":"BAG"},
   
{"key":"Iptc4xmpExt:RegistryId","namespace":"Iptc4xmpExt","valueType":"TEXT","cardinality":"BAG"},
+  
{"key":"License-Location","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
+  
{"key":"License-Url","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   {"key":"Location","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
+  {"key":"Work-Type","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"access-permission:assemble-document","namespace":"access-permission","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"access-permission:can-modify","namespace":"access-permission","valueType":"TEXT","cardinality":"BAG"},
   
{"key":"access-permission:can-print","namespace":"access-permission","valueType":"TEXT","cardinality":"SIMPLE"},
@@ -73,6 +77,7 @@
   
{"key":"access-permission:extract-for-accessibility","namespace":"access-permission","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"access-permission:fill-in-form","namespace":"access-permission","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"access-permission:modify-annotations","namespace":"access-permission","valueType":"TEXT","cardinality":"SIMPLE"},
+  
{"key":"acknowledgement","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"audio:bitrate","namespace":"audio","valueType":"INTEGER","cardinality":"SIMPLE"},
   
{"key":"audio:bits-per-sample","namespace":"audio","valueType":"INTEGER","cardinality":"SIMPLE"},
   
{"key":"audio:channels","namespace":"audio","valueType":"INTEGER","cardinality":"SIMPLE"},
@@ -86,6 +91,9 @@
   
{"key":"aux:LensID","namespace":"aux","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"aux:LensInfo","namespace":"aux","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"aux:SerialNumber","namespace":"aux","valueType":"TEXT","cardinality":"SIMPLE"},
+  {"key":"cmd_ln","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
+  {"key":"comment","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
+  {"key":"contact","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"cp:category","namespace":"cp","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"cp:contentStatus","namespace":"cp","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"cp:lastModifiedBy","namespace":"cp","valueType":"TEXT","cardinality":"SIMPLE"},
@@ -132,6 +140,7 @@
   
{"key":"exif:FocalLength","namespace":"exif","valueType":"RATIONAL","cardinality":"SIMPLE"},
   
{"key":"exif:IsoSpeedRatings","namespace":"exif","valueType":"INTEGER","cardinality":"SEQ"},
   
{"key":"exif:PageCount","namespace":"exif","valueType":"INTEGER","cardinality":"SIMPLE"},
+  
{"key":"experiment_id","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"extended-properties:AppVersion","namespace":"extended-properties","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"extended-properties:Application","namespace":"extended-properties","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"extended-properties:Company","namespace":"extended-properties","valueType":"TEXT","cardinality":"SIMPLE"},
@@ -160,7 +169,9 @@
   
{"key":"geo:lat","namespace":"geo","valueType":"REAL","cardinality":"SIMPLE"},
   
{"key":"geo:long","namespace":"geo","valueType":"REAL","cardinality":"SIMPLE"},
   
{"key":"geo:timestamp","namespace":"geo","valueType":"DATE","cardinality":"SIMPLE"},
+  {"key":"history","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"html:scriptSrc","namespace":"html","valueType":"TEXT","cardinality":"SIMPLE"},
+  
{"key":"institution","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"iworks:build-version-history","namespace":"iworks","valueType":"TEXT","cardinality":"BAG"},
   
{"key":"iworks:document-id","namespace":"iworks","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"machine:architectureBits","namespace":"machine","valueType":"CLOSED_CHOICE","cardinality":"SIMPLE"},
@@ -244,6 +255,7 @@
   
{"key":"meta:slide-count","namespace":"meta","valueType":"INTEGER","cardinality":"SIMPLE"},
   
{"key":"meta:table-count","namespace":"meta","valueType":"INTEGER","cardinality":"SIMPLE"},
   
{"key":"meta:word-count","namespace":"meta","valueType":"INTEGER","cardinality":"SIMPLE"},
+  
{"key":"model_name_english","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"msoffice:comment-person-display-name","namespace":"msoffice","valueType":"TEXT","cardinality":"BAG"},
   
{"key":"msoffice:doc:has-attached-template","namespace":"msoffice","valueType":"BOOLEAN","cardinality":"SIMPLE"},
   
{"key":"msoffice:doc:has-framesets","namespace":"msoffice","valueType":"BOOLEAN","cardinality":"SIMPLE"},
@@ -386,6 +398,8 @@
   
{"key":"plus:PropertyReleaseID","namespace":"plus","valueType":"TEXT","cardinality":"BAG"},
   
{"key":"plus:PropertyReleaseStatus","namespace":"plus","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"plus:Version","namespace":"plus","valueType":"TEXT","cardinality":"SIMPLE"},
+  {"key":"prg_ID","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
+  
{"key":"project_id","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"pst:discriptor-node-id","namespace":"pst","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"pst:is-valid","namespace":"pst","valueType":"BOOLEAN","cardinality":"SIMPLE"},
   
{"key":"quattropro:build","namespace":"quattropro","valueType":"INTEGER","cardinality":"SIMPLE"},
@@ -393,12 +407,16 @@
   
{"key":"quattropro:lowest-version","namespace":"quattropro","valueType":"INTEGER","cardinality":"SIMPLE"},
   
{"key":"quattropro:version","namespace":"quattropro","valueType":"INTEGER","cardinality":"SIMPLE"},
   
{"key":"quicktime:still-image-time","namespace":"quicktime","valueType":"REAL","cardinality":"SIMPLE"},
+  
{"key":"realization","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
+  
{"key":"references","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"rtf:contains-encapsulated-html","namespace":"rtf","valueType":"BOOLEAN","cardinality":"SIMPLE"},
   
{"key":"rtf:embedded-app-version","namespace":"rtf","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"rtf:embedded-class","namespace":"rtf","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"rtf:embedded-item","namespace":"rtf","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"rtf:embedded-topic","namespace":"rtf","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"rtf:thumbnail","namespace":"rtf","valueType":"BOOLEAN","cardinality":"SIMPLE"},
+  {"key":"source","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
+  {"key":"table_id","namespace":"","valueType":"TEXT","cardinality":"SIMPLE"},
   
{"key":"tess:image-magick-processed","namespace":"tess","valueType":"BOOLEAN","cardinality":"SEQ"},
   
{"key":"tess:orientation","namespace":"tess","valueType":"INTEGER","cardinality":"SIMPLE"},
   
{"key":"tess:orientation-confidence","namespace":"tess","valueType":"REAL","cardinality":"SIMPLE"},
diff --git 
a/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataNoUnderscoreTest.java
 
b/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataNoUnderscoreTest.java
index 7ee7600fab..ee799d7d0f 100644
--- 
a/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataNoUnderscoreTest.java
+++ 
b/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataNoUnderscoreTest.java
@@ -34,8 +34,16 @@ import org.junit.jupiter.api.Test;
  */
 public class MetadataNoUnderscoreTest {
 
-    /** Keys/prefixes whose underscore is an external standard's spelling 
(verbatim). Empty today. */
-    private static final Set<String> ALLOWLIST = Set.of();
+    /**
+     * Keys/prefixes whose underscore is an external standard's spelling 
(verbatim).
+     * {@code ClimateForcast} (tika-core) mints its 15 constants from the NCAR 
CCSM /
+     * Climate Forecast convention (http://cf-pcmdi.llnl.gov/) attribute names 
as-is; 6 of
+     * them carry the convention's own underscores. These are not Tika-coined, 
so renaming
+     * them is out of scope here (it would also change the keys Tika has 
emitted since 0.x).
+     */
+    private static final Set<String> ALLOWLIST = Set.of(
+            "prg_ID", "cmd_ln", "table_id", "project_id", "experiment_id",
+            "model_name_english");
 
     @Test
     public void noUnderscoreInTikaCoinedKeys() throws Exception {
diff --git 
a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/grib/GribParser.java
 
b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/grib/GribParser.java
index 94f819f9f2..2649b0dd20 100644
--- 
a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/grib/GribParser.java
+++ 
b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/grib/GribParser.java
@@ -21,7 +21,10 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
 import java.util.Collections;
+import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.apache.commons.io.FileUtils;
 import org.xml.sax.ContentHandler;
@@ -38,6 +41,7 @@ import org.apache.tika.io.TikaInputStream;
 import org.apache.tika.metadata.ClimateForcast;
 import org.apache.tika.metadata.KeyPrefix;
 import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.Property;
 import org.apache.tika.metadata.TikaCoreProperties;
 import org.apache.tika.mime.MediaType;
 import org.apache.tika.parser.ParseContext;
@@ -124,18 +128,23 @@ public class GribParser implements Parser {
         }
     }
 
-    private static final Set<String> CF_GLOBAL_ATTRIBUTES = Set.of(
-            ClimateForcast.PROGRAM_ID, ClimateForcast.COMMAND_LINE, 
ClimateForcast.HISTORY,
-            ClimateForcast.TABLE_ID, ClimateForcast.INSTITUTION, 
ClimateForcast.SOURCE,
-            ClimateForcast.CONTACT, ClimateForcast.PROJECT_ID, 
ClimateForcast.CONVENTIONS,
-            ClimateForcast.REFERENCES, ClimateForcast.ACKNOWLEDGEMENT, 
ClimateForcast.REALIZATION,
-            ClimateForcast.EXPERIMENT_ID, ClimateForcast.COMMENT, 
ClimateForcast.MODEL_NAME_ENGLISH);
+    private static final Map<String, Property> CF_GLOBAL_ATTRIBUTES = 
Stream.of(
+                    ClimateForcast.PROGRAM_ID, ClimateForcast.COMMAND_LINE, 
ClimateForcast.HISTORY,
+                    ClimateForcast.TABLE_ID, ClimateForcast.INSTITUTION, 
ClimateForcast.SOURCE,
+                    ClimateForcast.CONTACT, ClimateForcast.PROJECT_ID, 
ClimateForcast.CONVENTIONS,
+                    ClimateForcast.REFERENCES, ClimateForcast.ACKNOWLEDGEMENT,
+                    ClimateForcast.REALIZATION, ClimateForcast.EXPERIMENT_ID, 
ClimateForcast.COMMENT,
+                    ClimateForcast.MODEL_NAME_ENGLISH)
+            .collect(Collectors.toMap(Property::getName, p -> p));
 
     private static void addGlobalAttribute(Metadata metadata, String name, 
String value) {
         if ("title".equals(name)) {
             metadata.add(TikaCoreProperties.TITLE, value);
-        } else if (CF_GLOBAL_ATTRIBUTES.contains(name)) {
-            metadata.add(name, value);
+            return;
+        }
+        Property cfProperty = CF_GLOBAL_ATTRIBUTES.get(name);
+        if (cfProperty != null) {
+            metadata.add(cfProperty, value);
         } else {
             metadata.add(GRIB.key(name), value);
         }
diff --git 
a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/netcdf/NetCDFParser.java
 
b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/netcdf/NetCDFParser.java
index 1cc2cef3e2..364e7cd522 100644
--- 
a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/netcdf/NetCDFParser.java
+++ 
b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/netcdf/NetCDFParser.java
@@ -21,7 +21,10 @@ package org.apache.tika.parser.netcdf;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
@@ -36,6 +39,7 @@ import org.apache.tika.io.TikaInputStream;
 import org.apache.tika.metadata.ClimateForcast;
 import org.apache.tika.metadata.KeyPrefix;
 import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.Property;
 import org.apache.tika.metadata.TikaCoreProperties;
 import org.apache.tika.mime.MediaType;
 import org.apache.tika.parser.ParseContext;
@@ -133,18 +137,23 @@ public class NetCDFParser implements Parser {
         }
     }
 
-    private static final Set<String> CF_GLOBAL_ATTRIBUTES = Set.of(
-            ClimateForcast.PROGRAM_ID, ClimateForcast.COMMAND_LINE, 
ClimateForcast.HISTORY,
-            ClimateForcast.TABLE_ID, ClimateForcast.INSTITUTION, 
ClimateForcast.SOURCE,
-            ClimateForcast.CONTACT, ClimateForcast.PROJECT_ID, 
ClimateForcast.CONVENTIONS,
-            ClimateForcast.REFERENCES, ClimateForcast.ACKNOWLEDGEMENT, 
ClimateForcast.REALIZATION,
-            ClimateForcast.EXPERIMENT_ID, ClimateForcast.COMMENT, 
ClimateForcast.MODEL_NAME_ENGLISH);
+    private static final Map<String, Property> CF_GLOBAL_ATTRIBUTES = 
Stream.of(
+                    ClimateForcast.PROGRAM_ID, ClimateForcast.COMMAND_LINE, 
ClimateForcast.HISTORY,
+                    ClimateForcast.TABLE_ID, ClimateForcast.INSTITUTION, 
ClimateForcast.SOURCE,
+                    ClimateForcast.CONTACT, ClimateForcast.PROJECT_ID, 
ClimateForcast.CONVENTIONS,
+                    ClimateForcast.REFERENCES, ClimateForcast.ACKNOWLEDGEMENT,
+                    ClimateForcast.REALIZATION, ClimateForcast.EXPERIMENT_ID, 
ClimateForcast.COMMENT,
+                    ClimateForcast.MODEL_NAME_ENGLISH)
+            .collect(Collectors.toMap(Property::getName, p -> p));
 
     private static void addGlobalAttribute(Metadata metadata, String name, 
String value) {
         if ("title".equals(name)) {
             metadata.add(TikaCoreProperties.TITLE, value);
-        } else if (CF_GLOBAL_ATTRIBUTES.contains(name)) {
-            metadata.add(name, value);
+            return;
+        }
+        Property cfProperty = CF_GLOBAL_ATTRIBUTES.get(name);
+        if (cfProperty != null) {
+            metadata.add(cfProperty, value);
         } else {
             metadata.add(NETCDF.key(name), value);
         }
diff --git a/tika-xmp/src/main/java/org/apache/tika/xmp/XMPMetadata.java 
b/tika-xmp/src/main/java/org/apache/tika/xmp/XMPMetadata.java
index 888ca95e71..a89fa2cfbb 100644
--- a/tika-xmp/src/main/java/org/apache/tika/xmp/XMPMetadata.java
+++ b/tika-xmp/src/main/java/org/apache/tika/xmp/XMPMetadata.java
@@ -484,11 +484,12 @@ public class XMPMetadata extends Metadata {
     }
 
     /**
-     * It will set all simple and array properties that have QName keys in 
registered namespaces.
-     *
-     * @see org.apache.tika.metadata.Metadata#setAll(java.util.Properties)
+     * Sets all simple and array properties that have QName keys in registered 
namespaces.
+     * XMPMetadata-specific: no longer overrides a parent method (the raw-map
+     * {@code Metadata#setAll(Properties)} it used to override was removed as 
an
+     * unguarded write route; this method is a full reimplementation and never
+     * called {@code super}, so removal doesn't change its behavior).
      */
-    @Override
     public void setAll(Properties properties) {
         @SuppressWarnings("unchecked") Enumeration<String> names =
                 (Enumeration<String>) properties.propertyNames();

Reply via email to