Skip to content

Commit 3308262

Browse files
dmealingclaude
andcommitted
chore(java): pre-merge simplifier pass — metadata
Three small clarity tweaks on the six commits that closed the Java conformance ledger. Behavior-identical; 641/641 tests still green. * ValidationPhase.allowedOpsFor: replace inline subtype literals ("boolean", "date", "int" ...) with the existing *Field.SUBTYPE_* constants — matches the metamodel-strings-as-constants discipline. * ValidationPhase.validateDataGridLayout: route the @filterable attr reads through the file's existing ATTR_FILTERABLE constant (was duplicated as literal "filterable" twice); hoist the constant up so both readers share one declaration. * ValidationPhase.validateTemplateNode: prefix the three template error messages with ErrorMessageConstants.ERR_*: like every other ValidationPhase throw — restores log-readability parity. * CanonicalJsonSerializer.authoringPackageFor: drop the inline parent-instanceof-MetaRoot early-return (the next loop iteration already catches it at the top via the same resolveNodePackage call) and move the orphaned canonical-package Javadoc onto resolveNodePackage where it actually belongs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 76d60bc commit 3308262

2 files changed

Lines changed: 45 additions & 28 deletions

File tree

server/java/metadata/src/main/java/com/metaobjects/io/json/CanonicalJsonSerializer.java

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -357,17 +357,6 @@ private static List<MetaData> collectEffectiveStructuralChildren(MetaData node)
357357
// Helpers — package resolution
358358
// ---------------------------------------------------------------------------
359359

360-
/**
361-
* Returns the "canonical package" for a node.
362-
*
363-
* <p>For {@link MetaRoot}, the node's full {@link MetaData#getName()} IS the
364-
* package (e.g. {@code "acme::commerce"}). The default {@link MetaData#getPackage()}
365-
* would split on the last {@code ::} and return only the first segment
366-
* ({@code "acme"}), which is wrong for root nodes.</p>
367-
*
368-
* <p>For all other nodes the package is the prefix before the last {@code ::}
369-
* in the fully-qualified name, i.e. {@link MetaData#getPackage()} is correct.</p>
370-
*/
371360
/**
372361
* Returns the "authoring package" of a node — the package context an author
373362
* would use to write its {@code extends} ref. For root-level nodes this is
@@ -382,23 +371,30 @@ private static String authoringPackageFor(MetaData node) {
382371
if (current instanceof MetaRoot) {
383372
return resolveNodePackage(current);
384373
}
385-
// If we hit a non-root parent that isn't a MetaObject, keep walking
386-
// up — the goal is the nearest containing entity OR the root.
387374
MetaData parent = current.getParent();
388375
if (parent == null) break;
389-
if (parent instanceof MetaRoot) {
390-
// current's authoring context = root's package
391-
return resolveNodePackage(parent);
392-
}
393376
if (parent instanceof com.metaobjects.object.MetaObject) {
394377
// current is a child of an entity → authoring context = entity's package
395378
return parent.getPackage();
396379
}
380+
// Non-MetaObject parent (or MetaRoot): keep walking up; MetaRoot is
381+
// caught on the next iteration's top-of-loop check.
397382
current = parent;
398383
}
399384
return node.getPackage();
400385
}
401386

387+
/**
388+
* Returns the "canonical package" for a node.
389+
*
390+
* <p>For {@link MetaRoot}, the node's full {@link MetaData#getName()} IS the
391+
* package (e.g. {@code "acme::commerce"}). The default {@link MetaData#getPackage()}
392+
* would split on the last {@code ::} and return only the first segment
393+
* ({@code "acme"}), which is wrong for root nodes.</p>
394+
*
395+
* <p>For all other nodes the package is the prefix before the last {@code ::}
396+
* in the fully-qualified name, i.e. {@link MetaData#getPackage()} is correct.</p>
397+
*/
402398
private static String resolveNodePackage(MetaData node) {
403399
if (node instanceof MetaRoot) {
404400
// The root's name is the package itself — unless the loader had no

server/java/metadata/src/main/java/com/metaobjects/loader/ValidationPhase.java

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,19 @@
1111
import com.metaobjects.MetaDataException;
1212
import com.metaobjects.MetaRoot;
1313
import com.metaobjects.attr.MetaAttribute;
14+
import com.metaobjects.field.BooleanField;
15+
import com.metaobjects.field.CurrencyField;
16+
import com.metaobjects.field.DateField;
17+
import com.metaobjects.field.DecimalField;
18+
import com.metaobjects.field.DoubleField;
1419
import com.metaobjects.field.EnumField;
20+
import com.metaobjects.field.FloatField;
21+
import com.metaobjects.field.IntegerField;
22+
import com.metaobjects.field.LongField;
1523
import com.metaobjects.field.MetaField;
1624
import com.metaobjects.field.ObjectField;
25+
import com.metaobjects.field.TimeField;
26+
import com.metaobjects.field.TimestampField;
1727
import com.metaobjects.layout.DataGridLayout;
1828
import com.metaobjects.layout.MetaLayout;
1929
import com.metaobjects.identity.MetaIdentity;
@@ -773,6 +783,8 @@ private static void validateIdentityNode(MetaIdentity identity) {
773783
// Cross-port: mirrors TS validation-passes.ts (validateDataGridLayout).
774784
// =========================================================================
775785

786+
private static final String ATTR_FILTERABLE = "filterable";
787+
776788
private static final java.util.Set<String> OPS_FOR_BOOLEAN =
777789
java.util.Set.of("eq", "ne", "isNull");
778790
private static final java.util.Set<String> OPS_FOR_NUMERIC =
@@ -800,8 +812,8 @@ private static void validateDataGridLayout(MetaObject obj, DataGridLayout grid)
800812
java.util.Set<String> filterable = new java.util.HashSet<>();
801813
for (MetaField f : obj.getChildren(MetaField.class, true)) {
802814
fieldsByName.put(f.getShortName(), f);
803-
if (f.hasMetaAttr("filterable", false)) {
804-
Object v = f.getMetaAttr("filterable", false).getValue();
815+
if (f.hasMetaAttr(ATTR_FILTERABLE, false)) {
816+
Object v = f.getMetaAttr(ATTR_FILTERABLE, false).getValue();
805817
boolean isFilterable =
806818
(v instanceof Boolean) ? (Boolean) v
807819
: (v instanceof String) ? "true".equalsIgnoreCase((String) v)
@@ -880,10 +892,18 @@ private static void validateFilterClause(MetaObject obj, DataGridLayout grid,
880892

881893
private static java.util.Set<String> allowedOpsFor(MetaField field) {
882894
String st = field.getSubType();
883-
if ("boolean".equals(st)) return OPS_FOR_BOOLEAN;
884-
if ("date".equals(st) || "time".equals(st) || "timestamp".equals(st)) return OPS_FOR_DATE;
885-
if ("int".equals(st) || "long".equals(st) || "double".equals(st)
886-
|| "float".equals(st) || "decimal".equals(st) || "currency".equals(st)) {
895+
if (BooleanField.SUBTYPE_BOOLEAN.equals(st)) return OPS_FOR_BOOLEAN;
896+
if (DateField.SUBTYPE_DATE.equals(st)
897+
|| TimeField.SUBTYPE_TIME.equals(st)
898+
|| TimestampField.SUBTYPE_TIMESTAMP.equals(st)) {
899+
return OPS_FOR_DATE;
900+
}
901+
if (IntegerField.SUBTYPE_INT.equals(st)
902+
|| LongField.SUBTYPE_LONG.equals(st)
903+
|| DoubleField.SUBTYPE_DOUBLE.equals(st)
904+
|| FloatField.SUBTYPE_FLOAT.equals(st)
905+
|| DecimalField.SUBTYPE_DECIMAL.equals(st)
906+
|| CurrencyField.SUBTYPE_CURRENCY.equals(st)) {
887907
return OPS_FOR_NUMERIC;
888908
}
889909
// string / enum / others fall through to string-shape ops.
@@ -903,8 +923,6 @@ private static java.util.Set<String> allowedOpsFor(MetaField field) {
903923
// expected-warnings.json compare byte-equal.
904924
// =========================================================================
905925

906-
private static final String ATTR_FILTERABLE = "filterable";
907-
908926
static void warnFilterableWithoutIndex(MetaRoot root, MetaDataLoader loader) {
909927
if (loader == null) return;
910928
for (MetaData rootChild : root.getChildren(MetaData.class, false)) {
@@ -1025,7 +1043,8 @@ private static void validateTemplateNode(MetaRoot root, MetaTemplate template) {
10251043
if (TemplateConstants.SUBTYPE_PROMPT.equals(subType)
10261044
&& (payloadRef == null || payloadRef.isEmpty())) {
10271045
throw new MetaDataException(
1028-
"template.prompt '" + template.getName() + "' is missing required @payloadRef",
1046+
ErrorMessageConstants.ERR_MISSING_REQUIRED_ATTR
1047+
+ ": template.prompt '" + template.getName() + "' is missing required @payloadRef",
10291048
ErrorCode.ERR_MISSING_REQUIRED_ATTR);
10301049
}
10311050

@@ -1035,7 +1054,8 @@ private static void validateTemplateNode(MetaRoot root, MetaTemplate template) {
10351054
MetaObject payloadVo = findRootObject(root, payloadRef);
10361055
if (payloadVo == null || !MetaObject.SUBTYPE_VALUE.equals(payloadVo.getSubType())) {
10371056
throw new MetaDataException(
1038-
"template '" + template.getName() + "' @payloadRef '" + payloadRef
1057+
ErrorMessageConstants.ERR_INVALID_TEMPLATE
1058+
+ ": template '" + template.getName() + "' @payloadRef '" + payloadRef
10391059
+ "' does not resolve to an object.value at root",
10401060
ErrorCode.ERR_INVALID_TEMPLATE);
10411061
}
@@ -1050,7 +1070,8 @@ private static void validateTemplateNode(MetaRoot root, MetaTemplate template) {
10501070
if (slot == null || slot.isEmpty()) continue;
10511071
if (!available.contains(slot)) {
10521072
throw new MetaDataException(
1053-
"template.prompt '" + template.getName()
1073+
ErrorMessageConstants.ERR_INVALID_TEMPLATE
1074+
+ ": template.prompt '" + template.getName()
10541075
+ "' @requiredSlots includes '" + slot
10551076
+ "' which is not a field on payload '" + payloadRef + "'",
10561077
ErrorCode.ERR_INVALID_TEMPLATE);

0 commit comments

Comments
 (0)