diff --git a/java/change-notes/2021-04-02-add-spring-validation-errors.md b/java/change-notes/2021-04-02-add-spring-validation-errors.md new file mode 100644 index 00000000000..d3f7ee6e958 --- /dev/null +++ b/java/change-notes/2021-04-02-add-spring-validation-errors.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added additional taint steps modeling the Spring `validation.Errors` class (`org.springframework.validation.Errors`). diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll index f1a17c05723..39b79ca1ea1 100644 --- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll @@ -86,6 +86,7 @@ private module Frameworks { private import semmle.code.java.frameworks.Optional private import semmle.code.java.frameworks.spring.SpringHttp private import semmle.code.java.frameworks.spring.SpringUtil + private import semmle.code.java.frameworks.spring.SpringValidation private import semmle.code.java.frameworks.spring.SpringWebClient private import semmle.code.java.frameworks.spring.SpringBeans private import semmle.code.java.security.ResponseSplitting diff --git a/java/ql/src/semmle/code/java/frameworks/spring/Spring.qll b/java/ql/src/semmle/code/java/frameworks/spring/Spring.qll index 8a80e6a43d4..2cb2c5de64e 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/Spring.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/Spring.qll @@ -34,6 +34,7 @@ import semmle.code.java.frameworks.spring.SpringRef import semmle.code.java.frameworks.spring.SpringReplacedMethod import semmle.code.java.frameworks.spring.SpringSet import semmle.code.java.frameworks.spring.SpringUtil +import semmle.code.java.frameworks.spring.SpringValidation import semmle.code.java.frameworks.spring.SpringValue import semmle.code.java.frameworks.spring.SpringXMLElement import semmle.code.java.frameworks.spring.metrics.MetricSpringBean diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringValidation.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringValidation.qll new file mode 100644 index 00000000000..f536667f45b --- /dev/null +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringValidation.qll @@ -0,0 +1,25 @@ +/** Definitions of flow steps through utility methods of `org.springframework.validation.Errors`. */ + +import java +private import semmle.code.java.dataflow.ExternalFlow + +private class SpringValidationErrorModel extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "org.springframework.validation;Errors;true;addAllErrors;;;Argument[0];Argument[-1];taint", + "org.springframework.validation;Errors;true;getAllErrors;;;Argument[-1];ReturnValue;taint", + "org.springframework.validation;Errors;true;getFieldError;;;Argument[-1];ReturnValue;taint", + "org.springframework.validation;Errors;true;getFieldErrors;;;Argument[-1];ReturnValue;taint", + "org.springframework.validation;Errors;true;getGlobalError;;;Argument[-1];ReturnValue;taint", + "org.springframework.validation;Errors;true;getGlobalErrors;;;Argument[-1];ReturnValue;taint", + "org.springframework.validation;Errors;true;reject;;;Argument[0];Argument[-1];taint", + "org.springframework.validation;Errors;true;reject;;;ArrayElement of Argument[1];Argument[-1];taint", + "org.springframework.validation;Errors;true;reject;;;Argument[2];Argument[-1];taint", + "org.springframework.validation;Errors;true;rejectValue;;;Argument[1];Argument[-1];taint", + "org.springframework.validation;Errors;true;rejectValue;;;Argument[3];Argument[-1];taint", + "org.springframework.validation;Errors;true;rejectValue;(java.lang.String,java.lang.String,java.lang.Object[],java.lang.String);;ArrayElement of Argument[2];Argument[-1];taint", + "org.springframework.validation;Errors;true;rejectValue;(java.lang.String,java.lang.String,java.lang.String);;Argument[2];Argument[-1];taint" + ] + } +} diff --git a/java/ql/test/library-tests/frameworks/spring/validation/Test.java b/java/ql/test/library-tests/frameworks/spring/validation/Test.java new file mode 100644 index 00000000000..4f8aac5a335 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/spring/validation/Test.java @@ -0,0 +1,78 @@ +import org.springframework.validation.Errors; + +class ValidationErrorsTest { + Object source() { return null; } + + Errors sourceErrs() { return (Errors)source(); } + Errors errors() { return null; } + + void sink(Object o) {} + + void test() { + Errors es0 = errors(); + es0.addAllErrors(sourceErrs()); + sink(es0); // $hasTaintFlow + + sink(sourceErrs().getAllErrors()); // $hasTaintFlow + + sink(sourceErrs().getFieldError()); // $hasTaintFlow + sink(sourceErrs().getFieldError("field")); // $hasTaintFlow + + sink(sourceErrs().getGlobalError()); // $hasTaintFlow + sink(sourceErrs().getGlobalErrors()); // $hasTaintFlow + + Errors es1 = errors(); + es1.reject((String)source()); + sink(es1); // $hasTaintFlow + + Errors es2 = errors(); + es2.reject((String)source(), null, ""); + sink(es2); // $hasTaintFlow + + Errors es3 = errors(); + es3.reject((String)source(), null, ""); + sink(es3); // $hasTaintFlow + + { + Errors es4 = errors(); + Object[] in = { (String)source() }; + es4.reject("", in, ""); + sink(in); // $hasTaintFlow + } + + { + Errors es5 = errors(); + es5.reject("", null, (String)source()); + sink(es5); // $hasTaintFlow + } + + Errors es6 = errors(); + es6.reject((String)source(), ""); + sink(es6); // $hasTaintFlow + + Errors es7 = errors(); + es7.reject("", (String)source()); + sink(es7); // $hasTaintFlow + + Errors es8 = errors(); + es8.rejectValue("", (String)source(), null, ""); + sink(es8); // $hasTaintFlow + + Errors es9 = errors(); + Object[] in = {source()}; + es9.rejectValue("", "", in, ""); + sink(es9); // $hasTaintFlow + + Errors es10 = errors(); + es10.rejectValue("", "", null, (String)source()); + sink(es10); // $hasTaintFlow + + Errors es11 = errors(); + es11.rejectValue("", (String)source(), ""); + sink(es11); // $hasTaintFlow + + Errors es12 = errors(); + es12.rejectValue("", "", (String)source()); + sink(es12); // $hasTaintFlow + } +} diff --git a/java/ql/test/library-tests/frameworks/spring/validation/options b/java/ql/test/library-tests/frameworks/spring/validation/options new file mode 100644 index 00000000000..06ec85dc706 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/spring/validation/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8 diff --git a/java/ql/test/library-tests/frameworks/spring/validation/test.expected b/java/ql/test/library-tests/frameworks/spring/validation/test.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/library-tests/frameworks/spring/validation/test.ql b/java/ql/test/library-tests/frameworks/spring/validation/test.ql new file mode 100644 index 00000000000..6158159e1e5 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/spring/validation/test.ql @@ -0,0 +1,52 @@ +import java +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.TaintTracking +import TestUtilities.InlineExpectationsTest + +class ValueFlowConf extends DataFlow::Configuration { + ValueFlowConf() { this = "qltest:valueFlowConf" } + + override predicate isSource(DataFlow::Node n) { + n.asExpr().(MethodAccess).getMethod().hasName("source") + } + + override predicate isSink(DataFlow::Node n) { + n.asExpr().(Argument).getCall().getCallee().hasName("sink") + } +} + +class TaintFlowConf extends TaintTracking::Configuration { + TaintFlowConf() { this = "qltest:taintFlowConf" } + + override predicate isSource(DataFlow::Node n) { + n.asExpr().(MethodAccess).getMethod().hasName("source") + } + + override predicate isSink(DataFlow::Node n) { + n.asExpr().(Argument).getCall().getCallee().hasName("sink") + } +} + +class HasFlowTest extends InlineExpectationsTest { + HasFlowTest() { this = "HasFlowTest" } + + override string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasValueFlow" and + exists(DataFlow::Node src, DataFlow::Node sink, ValueFlowConf conf | conf.hasFlow(src, sink) | + sink.getLocation() = location and + element = sink.toString() and + value = "" + ) + or + tag = "hasTaintFlow" and + exists(DataFlow::Node src, DataFlow::Node sink, TaintFlowConf conf | + conf.hasFlow(src, sink) and not any(ValueFlowConf c).hasFlow(src, sink) + | + sink.getLocation() = location and + element = sink.toString() and + value = "" + ) + } +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/context/MessageSourceResolvable.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/context/MessageSourceResolvable.java new file mode 100644 index 00000000000..f64b1df5fd3 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/context/MessageSourceResolvable.java @@ -0,0 +1,29 @@ +/* + * Copyright 2002-2017 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.context; + +public interface MessageSourceResolvable { + String[] getCodes(); + + default Object[] getArguments() { + return null; + } + + default String getDefaultMessage() { + return null; + } +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/context/support/DefaultMessageSourceResolvable.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/context/support/DefaultMessageSourceResolvable.java new file mode 100644 index 00000000000..702b73926b7 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/context/support/DefaultMessageSourceResolvable.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.context.support; + +import java.io.Serializable; +import org.springframework.context.MessageSourceResolvable; +import org.springframework.lang.Nullable; + +public class DefaultMessageSourceResolvable implements MessageSourceResolvable, Serializable { + public DefaultMessageSourceResolvable(String code) {} + + public DefaultMessageSourceResolvable(String[] codes) {} + + public DefaultMessageSourceResolvable(String[] codes, String defaultMessage) {} + + public DefaultMessageSourceResolvable(String[] codes, Object[] arguments) {} + + public DefaultMessageSourceResolvable( + @Nullable String[] codes, @Nullable Object[] arguments, @Nullable String defaultMessage) {} + + public DefaultMessageSourceResolvable(MessageSourceResolvable resolvable) {} + + public String getCode() { + return null; + } + + @Override + public String[] getCodes() { + return null; + } + + @Override + public Object[] getArguments() { + return null; + } + + @Override + public String getDefaultMessage() { + return null; + } + + public boolean shouldRenderDefaultMessage() { + return false; + } + + @Override + public String toString() { + return null; + } + + @Override + public boolean equals(@Nullable Object other) { + return false; + } + + @Override + public int hashCode() { + return 0; + } + + protected final String resolvableToString() { + return null; + } +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/util/ObjectUtils.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/util/ObjectUtils.java index 06465de20fb..a6dece5a371 100644 --- a/java/ql/test/stubs/springframework-5.3.8/org/springframework/util/ObjectUtils.java +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/util/ObjectUtils.java @@ -1,50 +1,188 @@ -// Generated automatically from org.springframework.util.ObjectUtils for testing purposes +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.util; -abstract public class ObjectUtils -{ - public ObjectUtils(){} - public static A[] addObjectToArray(A[] p0, O p1){ return null; } - public static > E caseInsensitiveValueOf(E[] p0, String p1){ return null; } - public static Object unwrapOptional(Object p0){ return null; } - public static Object[] toObjectArray(Object p0){ return null; } - public static String getDisplayString(Object p0){ return null; } - public static String getIdentityHexString(Object p0){ return null; } - public static String identityToString(Object p0){ return null; } - public static String nullSafeClassName(Object p0){ return null; } - public static String nullSafeToString(Object p0){ return null; } - public static String nullSafeToString(Object[] p0){ return null; } - public static String nullSafeToString(boolean[] p0){ return null; } - public static String nullSafeToString(byte[] p0){ return null; } - public static String nullSafeToString(char[] p0){ return null; } - public static String nullSafeToString(double[] p0){ return null; } - public static String nullSafeToString(float[] p0){ return null; } - public static String nullSafeToString(int[] p0){ return null; } - public static String nullSafeToString(long[] p0){ return null; } - public static String nullSafeToString(short[] p0){ return null; } - public static boolean containsConstant(Enum[] p0, String p1){ return false; } - public static boolean containsConstant(Enum[] p0, String p1, boolean p2){ return false; } - public static boolean containsElement(Object[] p0, Object p1){ return false; } - public static boolean isArray(Object p0){ return false; } - public static boolean isCheckedException(Throwable p0){ return false; } - public static boolean isCompatibleWithThrowsClause(Throwable p0, Class... p1){ return false; } - public static boolean isEmpty(Object p0){ return false; } - public static boolean isEmpty(Object[] p0){ return false; } - public static boolean nullSafeEquals(Object p0, Object p1){ return false; } - public static int hashCode(boolean p0){ return 0; } - public static int hashCode(double p0){ return 0; } - public static int hashCode(float p0){ return 0; } - public static int hashCode(long p0){ return 0; } - public static int nullSafeHashCode(Object p0){ return 0; } - public static int nullSafeHashCode(Object[] p0){ return 0; } - public static int nullSafeHashCode(boolean[] p0){ return 0; } - public static int nullSafeHashCode(byte[] p0){ return 0; } - public static int nullSafeHashCode(char[] p0){ return 0; } - public static int nullSafeHashCode(double[] p0){ return 0; } - public static int nullSafeHashCode(float[] p0){ return 0; } - public static int nullSafeHashCode(int[] p0){ return 0; } - public static int nullSafeHashCode(long[] p0){ return 0; } - public static int nullSafeHashCode(short[] p0){ return 0; } +import org.springframework.lang.Nullable; + +public abstract class ObjectUtils { + public static boolean isCheckedException(Throwable ex) { + return false; + } + + public static boolean isCompatibleWithThrowsClause( + Throwable ex, @Nullable Class... declaredExceptions) { + return false; + } + + public static boolean isArray(@Nullable Object obj) { + return false; + } + + public static boolean isEmpty(@Nullable Object[] array) { + return false; + } + + public static boolean isEmpty(@Nullable Object obj) { + return false; + } + + public static Object unwrapOptional(@Nullable Object obj) { + return null; + } + + public static boolean containsElement(@Nullable Object[] array, Object element) { + return false; + } + + public static boolean containsConstant(Enum[] enumValues, String constant) { + return false; + } + + public static boolean containsConstant( + Enum[] enumValues, String constant, boolean caseSensitive) { + return false; + } + + public static > E caseInsensitiveValueOf(E[] enumValues, String constant) { + return null; + } + + public static A[] addObjectToArray(@Nullable A[] array, @Nullable O obj) { + return null; + } + + public static Object[] toObjectArray(@Nullable Object source) { + return null; + } + + public static boolean nullSafeEquals(@Nullable Object o1, @Nullable Object o2) { + return false; + } + + public static int nullSafeHashCode(@Nullable Object obj) { + return 0; + } + + public static int nullSafeHashCode(@Nullable Object[] array) { + return 0; + } + + public static int nullSafeHashCode(@Nullable boolean[] array) { + return 0; + } + + public static int nullSafeHashCode(@Nullable byte[] array) { + return 0; + } + + public static int nullSafeHashCode(@Nullable char[] array) { + return 0; + } + + public static int nullSafeHashCode(@Nullable double[] array) { + return 0; + } + + public static int nullSafeHashCode(@Nullable float[] array) { + return 0; + } + + public static int nullSafeHashCode(@Nullable int[] array) { + return 0; + } + + public static int nullSafeHashCode(@Nullable long[] array) { + return 0; + } + + public static int nullSafeHashCode(@Nullable short[] array) { + return 0; + } + + public static int hashCode(boolean bool) { + return 0; + } + + public static int hashCode(double dbl) { + return 0; + } + + public static int hashCode(float flt) { + return 0; + } + + public static int hashCode(long lng) { + return 0; + } + + public static String identityToString(@Nullable Object obj) { + return null; + } + + public static String getIdentityHexString(Object obj) { + return null; + } + + public static String getDisplayString(@Nullable Object obj) { + return null; + } + + public static String nullSafeClassName(@Nullable Object obj) { + return null; + } + + public static String nullSafeToString(@Nullable Object obj) { + return null; + } + + public static String nullSafeToString(@Nullable Object[] array) { + return null; + } + + public static String nullSafeToString(@Nullable boolean[] array) { + return null; + } + + public static String nullSafeToString(@Nullable byte[] array) { + return null; + } + + public static String nullSafeToString(@Nullable char[] array) { + return null; + } + + public static String nullSafeToString(@Nullable double[] array) { + return null; + } + + public static String nullSafeToString(@Nullable float[] array) { + return null; + } + + public static String nullSafeToString(@Nullable int[] array) { + return null; + } + + public static String nullSafeToString(@Nullable long[] array) { + return null; + } + + public static String nullSafeToString(@Nullable short[] array) { + return null; + } } diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/validation/Errors.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/validation/Errors.java new file mode 100644 index 00000000000..046f023f69c --- /dev/null +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/validation/Errors.java @@ -0,0 +1,84 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.validation; + +import java.util.List; +import org.springframework.lang.Nullable; + +public interface Errors { + String getObjectName(); + + void setNestedPath(String nestedPath); + + String getNestedPath(); + + void pushNestedPath(String subPath); + + void popNestedPath() throws IllegalStateException; + + void reject(String errorCode); + + void reject(String errorCode, String defaultMessage); + + void reject(String errorCode, @Nullable Object[] errorArgs, @Nullable String defaultMessage); + + void rejectValue(@Nullable String field, String errorCode); + + void rejectValue(@Nullable String field, String errorCode, String defaultMessage); + + void rejectValue( + @Nullable String field, + String errorCode, + @Nullable Object[] errorArgs, + @Nullable String defaultMessage); + + void addAllErrors(Errors errors); + + boolean hasErrors(); + + int getErrorCount(); + + List getAllErrors(); + + boolean hasGlobalErrors(); + + int getGlobalErrorCount(); + + List getGlobalErrors(); + + ObjectError getGlobalError(); + + boolean hasFieldErrors(); + + int getFieldErrorCount(); + + List getFieldErrors(); + + FieldError getFieldError(); + + boolean hasFieldErrors(String field); + + int getFieldErrorCount(String field); + + List getFieldErrors(String field); + + FieldError getFieldError(String field); + + Object getFieldValue(String field); + + Class getFieldType(String field); +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/validation/FieldError.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/validation/FieldError.java new file mode 100644 index 00000000000..d4a42bb9dd2 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/validation/FieldError.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.validation; + +import org.springframework.lang.Nullable; + +public class FieldError extends ObjectError { + public FieldError(String objectName, String field, String defaultMessage) { super("", ""); } + + public FieldError( + String objectName, + String field, + @Nullable Object rejectedValue, + boolean bindingFailure, + @Nullable String[] codes, + @Nullable Object[] arguments, + @Nullable String defaultMessage) { super("", ""); } + + public String getField() { + return null; + } + + @Nullable + public Object getRejectedValue() { + return null; + } + + public boolean isBindingFailure() { + return false; + } + + @Override + public boolean equals(@Nullable Object other) { + return false; + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public String toString() { + return null; + } +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/validation/ObjectError.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/validation/ObjectError.java new file mode 100644 index 00000000000..c7c6b244136 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/validation/ObjectError.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.validation; + +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.lang.Nullable; + +public class ObjectError extends DefaultMessageSourceResolvable { + + public ObjectError(String objectName, String defaultMessage) { super(""); } + + public ObjectError( + String objectName, + @Nullable String[] codes, + @Nullable Object[] arguments, + @Nullable String defaultMessage) { super(""); } + + public String getObjectName() { + return null; + } + + public void wrap(Object source) {} + + public T unwrap(Class sourceType) { + return null; + } + + public boolean contains(Class sourceType) { + return false; + } + + @Override + public boolean equals(@Nullable Object other) { + return false; + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public String toString() { + return ""; + } +}