Home / Class/ LambdaSafeCallback Class — spring-boot Architecture

LambdaSafeCallback Class — spring-boot Architecture

Architecture documentation for the LambdaSafeCallback class in LambdaSafe.java from the spring-boot codebase.

Entity Profile

Relationship Graph

Source Code

core/spring-boot/src/main/java/org/springframework/boot/util/LambdaSafe.java lines 105–233

	protected abstract static class LambdaSafeCallback<C, A, SELF extends LambdaSafeCallback<C, A, SELF>> {

		private final Class<C> callbackType;

		private final A argument;

		private final @Nullable Object @Nullable [] additionalArguments;

		private Log logger;

		private Filter<C, A> filter = new GenericTypeFilter<>();

		LambdaSafeCallback(Class<C> callbackType, A argument, @Nullable Object @Nullable [] additionalArguments) {
			this.callbackType = callbackType;
			this.argument = argument;
			this.additionalArguments = additionalArguments;
			this.logger = LogFactory.getLog(callbackType);
		}

		/**
		 * Use the specified logger source to report any lambda failures.
		 * @param loggerSource the logger source to use
		 * @return this instance
		 */
		public SELF withLogger(Class<?> loggerSource) {
			return withLogger(LogFactory.getLog(loggerSource));
		}

		/**
		 * Use the specified logger to report any lambda failures.
		 * @param logger the logger to use
		 * @return this instance
		 */
		public SELF withLogger(Log logger) {
			Assert.notNull(logger, "'logger' must not be null");
			this.logger = logger;
			return self();
		}

		/**
		 * Use a specific filter to determine when a callback should apply. If no explicit
		 * filter is set filter will be attempted using the generic type on the callback
		 * type.
		 * @param filter the filter to use
		 * @return this instance
		 * @since 3.4.8
		 */
		public SELF withFilter(Filter<C, A> filter) {
			Assert.notNull(filter, "'filter' must not be null");
			this.filter = filter;
			return self();
		}

		protected final <R> InvocationResult<R> invoke(C callbackInstance, Supplier<@Nullable R> supplier) {
			if (this.filter.match(this.callbackType, callbackInstance, this.argument, this.additionalArguments)) {
				try {
					return InvocationResult.of(supplier.get());
				}
				catch (ClassCastException ex) {
					if (!isLambdaGenericProblem(ex)) {
						throw ex;
					}
					logNonMatchingType(callbackInstance, ex);
				}
			}
			return InvocationResult.noResult();
		}

		private boolean isLambdaGenericProblem(ClassCastException ex) {
			return (ex.getMessage() == null || startsWithArgumentClassName(ex.getMessage()));
		}

		private boolean startsWithArgumentClassName(String message) {
			Predicate<@Nullable Object> startsWith = (argument) -> startsWithArgumentClassName(message, argument);
			return startsWith.test(this.argument) || additionalArgumentsStartsWith(startsWith);
		}

		private boolean additionalArgumentsStartsWith(Predicate<@Nullable Object> startsWith) {
			if (this.additionalArguments == null) {
				return false;
			}
			return Stream.of(this.additionalArguments).anyMatch(startsWith);
		}

		private boolean startsWithArgumentClassName(String message, @Nullable Object argument) {
			if (argument == null) {
				return false;
			}
			Class<?> argumentType = argument.getClass();
			// On Java 8, the message starts with the class name: "java.lang.String cannot
			// be cast..."
			if (message.startsWith(argumentType.getName())) {
				return true;
			}
			// On Java 11, the message starts with "class ..." a.k.a. Class.toString()
			if (message.startsWith(argumentType.toString())) {
				return true;
			}
			// On Java 9, the message used to contain the module name:
			// "java.base/java.lang.String cannot be cast..."
			int moduleSeparatorIndex = message.indexOf('/');
			if (moduleSeparatorIndex != -1 && message.startsWith(argumentType.getName(), moduleSeparatorIndex + 1)) {
				return true;
			}
			if (CLASS_GET_MODULE != null && MODULE_GET_NAME != null) {
				Object module = ReflectionUtils.invokeMethod(CLASS_GET_MODULE, argumentType);
				Object moduleName = ReflectionUtils.invokeMethod(MODULE_GET_NAME, module);
				return message.startsWith(moduleName + "/" + argumentType.getName());
			}
			return false;
		}

		private void logNonMatchingType(C callback, ClassCastException ex) {
			if (this.logger.isDebugEnabled()) {
				Class<?> expectedType = ResolvableType.forClass(this.callbackType).resolveGeneric();
				String expectedTypeName = (expectedType != null) ? ClassUtils.getShortName(expectedType) + " type"
						: "type";
				String message = "Non-matching " + expectedTypeName + " for callback "
						+ ClassUtils.getShortName(this.callbackType) + ": " + callback;
				this.logger.debug(message, ex);
			}
		}

		@SuppressWarnings("unchecked")
		private SELF self() {
			return (SELF) this;
		}

	}

Domain

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free