22 * SysML v2 REST/HTTP Pilot Implementation
33 * Copyright (C) 2020 InterCAX LLC
44 * Copyright (C) 2020 California Institute of Technology ("Caltech")
5- * Copyright (C) 2023 Twingineer LLC
5+ * Copyright (C) 2023-2025 Twingineer LLC
66 *
77 * This program is free software: you can redistribute it and/or modify
88 * it under the terms of the GNU Lesser General Public License as published by
2222
2323package org .omg .sysml .query .impl ;
2424
25- import com .fasterxml .jackson .annotation .JsonRawValue ;
25+ import com .fasterxml .jackson .annotation .JsonGetter ;
26+ import com .fasterxml .jackson .annotation .JsonProperty ;
27+ import com .fasterxml .jackson .annotation .JsonSetter ;
2628import com .fasterxml .jackson .annotation .JsonTypeName ;
29+ import com .fasterxml .jackson .core .JsonGenerator ;
2730import com .fasterxml .jackson .core .JsonProcessingException ;
2831import com .fasterxml .jackson .databind .JsonNode ;
32+ import com .fasterxml .jackson .databind .SerializerProvider ;
2933import com .fasterxml .jackson .databind .annotation .JsonDeserialize ;
34+ import com .fasterxml .jackson .databind .annotation .JsonSerialize ;
3035import com .fasterxml .jackson .databind .deser .std .JsonNodeDeserializer ;
36+ import com .fasterxml .jackson .databind .ser .std .StdSerializer ;
37+ import javabean .JavaBeanHelper ;
3138import org .omg .sysml .query .PrimitiveConstraint ;
3239import org .omg .sysml .query .PrimitiveOperator ;
3340import play .libs .Json ;
3441
42+ import javax .annotation .Nullable ;
3543import javax .persistence .*;
44+ import java .io .IOException ;
45+ import java .util .ArrayList ;
46+ import java .util .Collections ;
47+ import java .util .List ;
48+ import java .util .UUID ;
3649
3750// @Embeddable // Can't embed and have polymorphism between Constraints, which is necessary for CompositeConstraint.constraint
3851@ Entity (name = "PrimitiveConstraint" )
4154public class PrimitiveConstraintImpl extends ConstraintImpl implements PrimitiveConstraint {
4255 private Boolean inverse ;
4356 private String property ;
44- private String value ;
57+ private List < String > value ;
4558 private PrimitiveOperator operator ;
4659
4760 @ Override
@@ -60,6 +73,7 @@ public void setInverse(Boolean inverse) {
6073
6174 @ Override
6275 @ Column
76+ @ JsonProperty (required = true )
6377 public String getProperty () {
6478 return property ;
6579 }
@@ -70,23 +84,54 @@ public void setProperty(String property) {
7084 }
7185
7286 @ Override
73- @ Column
74- @ JsonRawValue
75- public String getValue () {
76- return value != null ? value : "null" ;
87+ @ JsonProperty (required = true )
88+ @ JsonSerialize (contentUsing = RawValueSerializer .class )
89+ @ Lob
90+ @ org .hibernate .annotations .Type (type = "org.hibernate.type.TextType" )
91+ @ ElementCollection (targetClass = String .class , fetch = FetchType .EAGER )
92+ @ CollectionTable
93+ public @ Nullable List <String > getValue () {
94+ return value .isEmpty () ? null : value ;
7795 }
7896
79- @ JsonDeserialize (using = OpenJsonNodeDeserializer .class )
80- public void setValue (JsonNode value ) throws JsonProcessingException {
81- this .value = value != null ? Json .mapper ().writeValueAsString (value ) : "null" ;
97+ public void setValue (@ Nullable List <String > value ) {
98+ this .value = value == null ? Collections .emptyList () : value ;
99+ }
100+
101+ @ JsonSetter ("value" )
102+ @ JsonDeserialize (contentUsing = OpenJsonNodeDeserializer .class )
103+ public void setValueJson (@ Nullable List <JsonNode > value ) throws JsonProcessingException {
104+ if (value == null ) {
105+ this .value = Collections .emptyList ();
106+ return ;
107+ }
108+ if (value .isEmpty ()) {
109+ throw new IllegalArgumentException ("value must not be empty" );
110+ }
111+
112+ List <String > result = new ArrayList <>(value .size ());
113+ for (JsonNode node : value ) {
114+ if (node .isBoolean () || node .isNumber () || node .isTextual ()) {
115+ result .add (Json .mapper ().writeValueAsString (node ));
116+ } else if (node .isObject ()) {
117+ if (node .size () != 1 ) {
118+ throwBadValue ();
119+ }
120+ if (extractId (node ) == null ) {
121+ throwBadValue ();
122+ }
123+ result .add (Json .mapper ().writeValueAsString (node ));
124+ } else {
125+ throwBadValue ();
126+ }
127+ }
128+ this .value = result ;
82129 }
83130
84131 @ Override
85132 @ Enumerated (EnumType .STRING )
133+ @ JsonProperty (required = true )
86134 public PrimitiveOperator getOperator () {
87- if (operator == null ) {
88- operator = PrimitiveOperator .EQUALS ;
89- }
90135 return operator ;
91136 }
92137
@@ -95,6 +140,29 @@ public void setOperator(PrimitiveOperator operator) {
95140 this .operator = operator ;
96141 }
97142
143+ public static @ Nullable UUID extractId (JsonNode node ) {
144+ return JavaBeanHelper .convert (
145+ // intentionally `textValue` instead of `asText` to get a null value for improved error reporting
146+ node .path ("@id" ).textValue (),
147+ UUID .class
148+ );
149+ }
150+
151+ private static void throwBadValue () {
152+ throw new IllegalArgumentException ("value must be typed boolean, number, string, or Identified" );
153+ }
154+
155+ public static final class RawValueSerializer extends StdSerializer <String > {
156+ public RawValueSerializer () {
157+ super (String .class );
158+ }
159+
160+ @ Override
161+ public void serialize (String value , JsonGenerator gen , SerializerProvider provider ) throws IOException {
162+ gen .writeRawValue (value );
163+ }
164+ }
165+
98166 public static final class OpenJsonNodeDeserializer extends JsonNodeDeserializer {
99167 public OpenJsonNodeDeserializer () {
100168 super ();
0 commit comments