1 /* 2 * ************************************************************************************************************************************************************* 3 * 4 * TheseFoolishThings: Miscellaneous utilities 5 * http://tidalwave.it/projects/thesefoolishthings 6 * 7 * Copyright (C) 2009 - 2025 by Tidalwave s.a.s. (http://tidalwave.it) 8 * 9 * ************************************************************************************************************************************************************* 10 * 11 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 12 * You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * 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 17 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 18 * 19 * ************************************************************************************************************************************************************* 20 * 21 * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src 22 * git clone https://github.com/tidalwave-it/thesefoolishthings-src 23 * 24 * ************************************************************************************************************************************************************* 25 */ 26 package it.tidalwave.util; 27 28 import java.lang.reflect.InvocationTargetException; 29 import jakarta.annotation.Nonnull; 30 import jakarta.annotation.Nullable; 31 import java.util.Arrays; 32 import java.util.List; 33 import lombok.extern.slf4j.Slf4j; 34 import static java.util.stream.Collectors.*; 35 36 /*************************************************************************************************************************************************************** 37 * 38 * A utility that returns short qualified names for class literals and objects. 39 * 40 * @author Fabrizio Giudici 41 * @since 3.2-ALPHA-17 42 * 43 **************************************************************************************************************************************************************/ 44 @Slf4j 45 public class ShortNames 46 { 47 /*********************************************************************************************************************************************************** 48 * Returns the short name for a class literal. 49 * 50 * @param clazz the class 51 * @return the short name 52 **********************************************************************************************************************************************************/ 53 @Nonnull 54 public static String shortName (@Nonnull final Class<?> clazz) 55 { 56 return shortName(clazz, false); 57 } 58 59 /*********************************************************************************************************************************************************** 60 * Returns the short name for a class literal, eventually adding interface names (but not those in the java.* 61 * package). 62 * 63 * @param clazz the class 64 * @param withInterfaces whether the interfaces must be listed 65 * @return the short name 66 **********************************************************************************************************************************************************/ 67 @Nonnull 68 public static String shortName (@Nonnull final Class<?> clazz, final boolean withInterfaces) 69 { 70 var className = clazz.getName(); 71 var prefix = ""; 72 73 if (className.contains("EnhancerByMockito")) 74 { 75 prefix = "mock-of-"; 76 className = className.replaceAll("\\$\\$EnhancerByMockito.*", ""); 77 } 78 79 final var parts = className.split("\\."); 80 final var s = new StringBuilder(); 81 82 for (var i = 0; i < parts.length; i++) 83 { 84 s.append((i < parts.length - 1) ? parts[i].charAt(0) + "." : parts[i]); 85 } 86 87 if (withInterfaces) 88 { 89 final var interfaces = clazz.getInterfaces(); 90 91 if (interfaces.length > 0) 92 { 93 s.append(Arrays.stream(interfaces) 94 .filter(i -> !i.getPackage().getName().startsWith("java")) 95 .map(ShortNames::shortName).collect(joining(", ", "{", "}"))); 96 } 97 } 98 99 return prefix + s; 100 } 101 102 /*********************************************************************************************************************************************************** 103 * Returns the short name for class literals, eventually adding interface names (but not those in the java.* 104 * package). 105 * 106 * @param classes the classes 107 * @return the short names 108 **********************************************************************************************************************************************************/ 109 @Nonnull 110 public static String shortNames (@Nonnull final Iterable<Class<?>> classes) 111 { 112 final var result = new StringBuilder(); 113 var separator = ""; 114 115 for (final var clazz : classes) 116 { 117 result.append(separator).append(shortName(clazz)); 118 separator = ", "; 119 } 120 121 return "[" + result + "]"; 122 } 123 124 /*********************************************************************************************************************************************************** 125 * Return the short name for an object. If the object contains a method named {@code getId()}, the id is part of 126 * the result. 127 * 128 * @param object the object 129 * @return the short name 130 **********************************************************************************************************************************************************/ 131 @Nonnull 132 public static String shortId (@Nullable final Object object) 133 { 134 if (object == null) 135 { 136 return "null"; 137 } 138 139 final var s = new StringBuilder(); 140 s.append(String.format("%s@%x", shortName(object.getClass()), System.identityHashCode(object))); 141 142 try 143 { 144 final var id = object.getClass().getMethod("getId").invoke(object); 145 s.append("/").append(id != null ? id.toString() : "null"); 146 } 147 catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ignored) 148 { 149 // log.trace("While invoking 'getId(): {}", e.toString()); 150 } 151 152 return s.toString(); 153 } 154 155 /*********************************************************************************************************************************************************** 156 * Return the short names for some objects. 157 * 158 * @param objects the objects 159 * @return the short names 160 **********************************************************************************************************************************************************/ 161 @Nonnull 162 public static String shortIds (@Nonnull final Iterable<?> objects) 163 { 164 final var result = new StringBuilder(); 165 var separator = ""; 166 167 for (final var object : objects) 168 { 169 result.append(separator).append(shortId(object)); 170 separator = ", "; 171 } 172 173 return "[" + result + "]"; 174 } 175 176 /*********************************************************************************************************************************************************** 177 * Return the short names for some objects. 178 * 179 * @param objects the objects 180 * @return the short names 181 **********************************************************************************************************************************************************/ 182 @Nonnull 183 public static String shortIds (@Nonnull final Object... objects) 184 { 185 return shortIds(List.of(objects)); 186 } 187 }