davsclaus commented on code in PR #27367: URL: https://github.com/apache/camel/pull/27367#discussion_r4181852575
########## dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/TextBodyFlow.java: ########## @@ -0,0 +1,476 @@ +/* + * 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.camel.dsl.yaml.validator; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.Error; +import com.networknt.schema.path.NodePath; +import org.apache.camel.util.MimeTypeHelper; + +import static org.apache.camel.dsl.yaml.validator.RouteGraph.endpointOf; +import static org.apache.camel.dsl.yaml.validator.RouteGraph.normalize; +import static org.apache.camel.dsl.yaml.validator.RouteGraph.scheme; + +/** + * A field read on a body that is still text. + * <p/> + * Groovy {@code body.find { it.sku == ... }} or simple {@code ${body[sku]}} reads the fields of parsed data: a Map or a + * List. When the step before left the payload as text - a {@code setBody} with {@code constant}, a {@code marshal}, the + * file consumer, or a {@code direct:} route that ends with one of those - the read fails at runtime, Groovy with "No + * such property: sku for class: java.lang.Byte". The walk follows the steps of each route in order, and into the + * {@code direct:} and {@code seda:} routes it calls, and reports only where it is certain the body is text: anything it + * does not know makes it say nothing (CAMEL-24844). + */ +final class TextBodyFlow { + + /** The Groovy methods that iterate a collection with a closure; on text they iterate the characters or bytes. */ + private static final Set<String> ITERATES = Set.of("find", "findAll", "each", "eachWithIndex", "collect", + "collectEntries", "any", "every", "grep", "count", "sum", "findResult", "groupBy", "sort", "max", "min"); + + /** The methods of a Map, which text does not have. */ + private static final Set<String> MAP_METHODS = Set.of("get", "getAt", "containsKey", "keySet", "values", + "entrySet"); + + /** What can be read from text without parsing it: a property of String, or a Groovy property of text. */ + private static final Set<String> TEXT_PROPERTIES = Set.of("bytes", "text", "class", "empty", "blank", "length", + "size", "toString", "trim", "lines", "chars", "hashCode"); + + /** What the file consumer's GenericFile has besides: ${body.fileName} reads the file, not its content. */ + private static final Set<String> FILE_PROPERTIES = Set.of("file", "fileName", "fileNameOnly", "fileLength", + "lastModified", "charset", "extendedAttributes", "body", "parent", "absoluteFilePath", "relativeFilePath", + "absolute", "endpointPath", "directory", "copyFromAbsoluteFilePath", "lastOffsetValue", "fileSeparator", + "binding"); + + /** body.x, body?.x, message.body.x, followed by what comes after the name. */ + private static final Pattern GROOVY_PROPERTY = Pattern.compile("(?<![\\w$])body\\s*\\??\\.\\s*([A-Za-z_]\\w*)\\s*([{(])?"); + + /** body['x'] or body["x"]. */ + private static final Pattern GROOVY_KEY = Pattern.compile("(?<![\\w$])body\\s*\\[\\s*['\"]"); + + /** ${body.x} or ${body?.x}, not a method call. */ + private static final Pattern SIMPLE_PROPERTY = Pattern.compile("\\$\\{body\\??\\.([A-Za-z_]\\w*)(?!\\w|\\s*\\()"); + + /** ${body[x]} where x is a key, not an index. */ + private static final Pattern SIMPLE_KEY = Pattern.compile("\\$\\{body\\[\\s*['\"]?[A-Za-z_]"); Review Comment: Fixed in 1d0506a52fab: the Groovy key read now guards the index the way `simpleRead` does, and an unclosed `body['sku` is reported with `body['`. `testAnUnclosedKeyIsStillReported` covers both readers. _Claude Code on behalf of davsclaus_ -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
