Content of file ShortNames.java
/* * ********************************************************************************************************************* * * TheseFoolishThings: Miscellaneous utilities * http://tidalwave.it/projects/thesefoolishthings * * Copyright (C) 2009 - 2024 by Tidalwave s.a.s. (http://tidalwave.it) * * ********************************************************************************************************************* * * 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 * * 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. * * ********************************************************************************************************************* * * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src * git clone https://github.com/tidalwave-it/thesefoolishthings-src * * ********************************************************************************************************************* */ package it.tidalwave.util; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Arrays; import java.util.List; import lombok.extern.slf4j.Slf4j; import static java.util.stream.Collectors.*; /*********************************************************************************************************************** * * A utility that returns short qualified names for class literals and objects. * * @author Fabrizio Giudici * @since 3.2-ALPHA-17 * **********************************************************************************************************************/ @Slf4j public class ShortNames { /******************************************************************************************************************* * * Returns the short name for a class literal. * * @param clazz the class * @return the short name * ******************************************************************************************************************/ @Nonnull public static String shortName (@Nonnull final Class<?> clazz) { return shortName(clazz, false); } /******************************************************************************************************************* * * Returns the short name for a class literal, eventually adding interface names (but not those in the java.* * package). * * @param clazz the class * @param withInterfaces whether the interfaces must be listed * @return the short name * ******************************************************************************************************************/ @Nonnull public static String shortName (@Nonnull final Class<?> clazz, final boolean withInterfaces) { var className = clazz.getName(); var prefix = ""; if (className.contains("EnhancerByMockito")) { prefix = "mock-of-"; className = className.replaceAll("\\$\\$EnhancerByMockito.*", ""); } final var parts = className.split("\\."); final var s = new StringBuilder(); for (var i = 0; i < parts.length; i++) { s.append((i < parts.length - 1) ? parts[i].charAt(0) + "." : parts[i]); } if (withInterfaces) { final var interfaces = clazz.getInterfaces(); if (interfaces.length > 0) { s.append(Arrays.stream(interfaces) .filter(i -> !i.getPackage().getName().startsWith("java")) .map(ShortNames::shortName).collect(joining(", ", "{", "}"))); } } return prefix + s; } /******************************************************************************************************************* * * Returns the short name for class literals, eventually adding interface names (but not those in the java.* * package). * * @param classes the classes * @return the short names * ******************************************************************************************************************/ @Nonnull public static String shortNames (@Nonnull final Iterable<Class<?>> classes) { final var result = new StringBuilder(); var separator = ""; for (final var clazz : classes) { result.append(separator).append(shortName(clazz)); separator = ", "; } return "[" + result + "]"; } /******************************************************************************************************************* * * Return the short name for an object. If the object contains a method named {@code getId()}, the id is part of * the result. * * @param object the object * @return the short name * ******************************************************************************************************************/ @Nonnull public static String shortId (@Nullable final Object object) { if (object == null) { return "null"; } final var s = new StringBuilder(); s.append(String.format("%s@%x", shortName(object.getClass()), System.identityHashCode(object))); try { final var id = object.getClass().getMethod("getId").invoke(object); s.append("/").append(id != null ? id.toString() : "null"); }
catch (Exception e)
This method uses a try-catch block that catches Exception objects, but Exception is not thrown within the try block, and RuntimeException is not explicitly caught. It is a common bug pattern to say try { ... } catch (Exception e) { something } as a shorthand for catching a number of types of exception each of whose catch blocks is identical, but this construct also accidentally catches RuntimeException as well, masking potential bugs.
A better approach is to either explicitly catch the specific exceptions that are thrown, or to explicitly catch RuntimeException exception, rethrow it, and then catch all non-Runtime Exceptions, as shown below:
try { ... } catch (RuntimeException e) { throw e; } catch (Exception e) { ... deal with all non-runtime exceptions ... }
{ // log.trace("While invoking 'getId(): {}", e.toString()); } return s.toString(); } /******************************************************************************************************************* * * Return the short names for some objects. * * @param objects the objects * @return the short names * ******************************************************************************************************************/ @Nonnull public static String shortIds (@Nonnull final Iterable<?> objects) { final var result = new StringBuilder(); var separator = ""; for (final Object object : objects) { result.append(separator).append(shortId(object)); separator = ", "; } return "[" + result + "]"; } /******************************************************************************************************************* * * Return the short names for some objects. * * @param objects the objects * @return the short names * ******************************************************************************************************************/ @Nonnull public static String shortIds (@Nonnull final Object... objects) { return shortIds(List.of(objects)); } }