001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.util.struct; 006 007import java.util.Optional; 008 009/** 010 * A utility class for fetching the assigned struct of existing classes. These are usually public, 011 * static, and final properties with the Struct type. 012 */ 013public final class StructFetcher { 014 private StructFetcher() { 015 throw new UnsupportedOperationException("This is a utility class!"); 016 } 017 018 /** 019 * Returns a {@link Struct} for the given {@link StructSerializable} marked class. Due to the 020 * non-contractual nature of the marker this can fail. If the {@code struct} field could not be 021 * accessed for any reason, an empty {@link Optional} is returned. 022 * 023 * @param <T> The type of the class. 024 * @param clazz The class object to extract the struct from. 025 * @return An optional containing the struct if it could be extracted. 026 */ 027 @SuppressWarnings("unchecked") 028 public static <T extends StructSerializable> Optional<Struct<T>> fetchStruct( 029 Class<? extends T> clazz) { 030 try { 031 var possibleField = Optional.ofNullable(clazz.getDeclaredField("struct")); 032 return possibleField.flatMap( 033 field -> { 034 if (Struct.class.isAssignableFrom(field.getType())) { 035 try { 036 return Optional.ofNullable((Struct<T>) field.get(null)); 037 } catch (IllegalAccessException e) { 038 return Optional.empty(); 039 } 040 } else { 041 return Optional.empty(); 042 } 043 }); 044 } catch (NoSuchFieldException e) { 045 return Optional.empty(); 046 } 047 } 048 049 /** 050 * Returns a {@link Struct} for the given class. This does not do compile time checking that the 051 * class is a {@link StructSerializable}. Whenever possible it is reccomended to use {@link 052 * #fetchStruct(Class)}. 053 * 054 * @param clazz The class object to extract the struct from. 055 * @return An optional containing the struct if it could be extracted. 056 */ 057 @SuppressWarnings("unchecked") 058 public static Optional<Struct<?>> fetchStructDynamic(Class<?> clazz) { 059 if (StructSerializable.class.isAssignableFrom(clazz)) { 060 return fetchStruct((Class<? extends StructSerializable>) clazz).map(struct -> struct); 061 } else { 062 return Optional.empty(); 063 } 064 } 065}