001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.rest.server.validation;
018
019import org.apache.juneau.marshall.*;
020
021/**
022 * Wire-friendly snapshot of a single Jakarta Bean Validation constraint violation, suitable for inclusion in an
023 * HTTP error response body.
024 *
025 * <p>
026 * Produced by {@link BeanValidator} from a {@code jakarta.validation.ConstraintViolation}, with deliberately
027 * narrow surface so the bean is decoupled from the optional {@code jakarta.validation} runtime dependency. The
028 * {@link #invalidValue} field is omitted by default to avoid echoing potentially sensitive request data back to
029 * the client; callers can opt back in via {@link #setInvalidValue(String)}.
030 *
031 * <h5 class='section'>JSON shape:</h5>
032 * <p class='bjson'>
033 *    {
034 *       <jok>"path"</jok>: <jov>"name"</jov>,
035 *       <jok>"message"</jok>: <jov>"must not be blank"</jov>,
036 *       <jok>"constraint"</jok>: <jov>"NotBlank"</jov>
037 *    }
038 * </p>
039 *
040 * <h5 class='section'>See Also:</h5><ul>
041 *    <li class='jc'>{@link ValidationException}
042 *    <li class='jc'>{@link BeanValidator}
043 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerValidation">Jakarta Bean Validation</a>
044 * </ul>
045 *
046 * @since 10.0.0
047 */
048@Marshalled
049public class ValidationViolation {
050
051   private String path;
052   private String message;
053   private String constraint;
054   private String invalidValue;
055
056   /**
057    * Default constructor.
058    */
059   public ValidationViolation() {}
060
061   /**
062    * Convenience constructor populating the three non-sensitive fields.
063    *
064    * @param path The property path string (e.g. {@code "name"} or {@code "items[2].sku"}). May be <jk>null</jk>.
065    * @param message The localized violation message produced by the constraint validator. May be <jk>null</jk>.
066    * @param constraint The simple name of the constraint annotation (e.g. {@code "NotBlank"}). May be <jk>null</jk>.
067    */
068   public ValidationViolation(String path, String message, String constraint) {
069      this.path = path;
070      this.message = message;
071      this.constraint = constraint;
072   }
073
074   /**
075    * The Jakarta-Validation property path string &mdash; the dotted/indexed path from the validated root bean
076    * down to the violating field (e.g. {@code "name"} or {@code "items[2].sku"}).
077    *
078    * @return The property path, or <jk>null</jk> if not set.
079    */
080   public String getPath() { return path; }
081
082   /**
083    * Sets the property path.
084    *
085    * @param value The new value. Can be <jk>null</jk> to unset the property.
086    * @return This object.
087    */
088   public ValidationViolation setPath(String value) {
089      path = value;
090      return this;
091   }
092
093   /**
094    * The localized violation message from the constraint validator (e.g. {@code "must not be blank"}).
095    *
096    * @return The message, or <jk>null</jk> if not set.
097    */
098   public String getMessage() { return message; }
099
100   /**
101    * Sets the message.
102    *
103    * @param value The new value. Can be <jk>null</jk> to unset the property.
104    * @return This object.
105    */
106   public ValidationViolation setMessage(String value) {
107      message = value;
108      return this;
109   }
110
111   /**
112    * The simple name of the constraint annotation that was violated (e.g. {@code "NotBlank"}, {@code "Size"}).
113    *
114    * @return The constraint name, or <jk>null</jk> if not set.
115    */
116   public String getConstraint() { return constraint; }
117
118   /**
119    * Sets the constraint.
120    *
121    * @param value The new value. Can be <jk>null</jk> to unset the property.
122    * @return This object.
123    */
124   public ValidationViolation setConstraint(String value) {
125      constraint = value;
126      return this;
127   }
128
129   /**
130    * The (string-rendered) invalid value that triggered the violation.
131    *
132    * <p>
133    * Omitted by default to avoid echoing potentially sensitive request data back to the client; populated only
134    * when the caller explicitly opts in via {@link #setInvalidValue(String)} (typically from a
135    * {@code BeanValidator} configured with {@code includeInvalidValue(true)}).
136    *
137    * @return The invalid value, or <jk>null</jk> if not set.
138    */
139   public String getInvalidValue() { return invalidValue; }
140
141   /**
142    * Sets the invalid value.
143    *
144    * @param value The new value. Can be <jk>null</jk> to unset the property.
145    * @return This object.
146    */
147   public ValidationViolation setInvalidValue(String value) {
148      invalidValue = value;
149      return this;
150   }
151}