All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.cookiecode.stylesniffer.StyleSnifferImpl Maven / Gradle / Ivy

The newest version!
/*
 * The MIT License
 * Copyright © 2024 Sebastien Vermeille
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package dev.cookiecode.stylesniffer;

import static java.lang.reflect.Modifier.isAbstract;
import static java.util.Collections.unmodifiableList;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toSet;

import com.google.common.annotations.VisibleForTesting;
import dev.cookiecode.stylesniffer.api.CaseStyle;
import dev.cookiecode.stylesniffer.api.exception.StyleSnifferException;
import jakarta.annotation.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.NonNull;

/**
 * The {@code StyleSniffer} class is responsible for managing and detecting various {@link
 * CaseStyle} implementations.
 *
 * 

It registers all case style classes that are annotated with {@link * dev.cookiecode.stylesniffer.annotation.RegisterCaseStyle}, instantiates them, and stores them in * a list. It also provides methods to retrieve case styles based on names and to list all supported * case styles. * * @author Sebastien Vermeille */ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class StyleSnifferImpl implements StyleSniffer { private List caseStyles = new ArrayList<>(); StyleSnifferImpl(@NonNull List> caseStyleClasses) { registerCaseStyleClasses(caseStyleClasses); } @VisibleForTesting void registerCaseStyleClass(@NonNull Class caseStyleClass) { registerCaseStyleClasses(Collections.singletonList(caseStyleClass)); } @VisibleForTesting void registerCaseStyleClasses(@NonNull List> caseStyleClasses) { List newCaseStyles = new ArrayList<>(caseStyles); newCaseStyles.addAll( caseStyleClasses.stream() .filter(this::isValidCaseStyleClass) .map(this::instantiateCaseStyle) .toList()); caseStyles = unmodifiableList( newCaseStyles); // ensure only this method can modify caseStyles items (no add nor // delete) } /** * Checks if the given class is a valid {@link CaseStyle} implementation. * * @param clazz the class to check * @return {@code true} if the class is a valid {@code CaseStyle} implementation; {@code false} * otherwise */ @VisibleForTesting boolean isValidCaseStyleClass(Class clazz) { return CaseStyle.class.isAssignableFrom(clazz) && !isAbstract(clazz.getModifiers()); } /** * Instantiates a {@link CaseStyle} class. * * @param clazz the class to instantiate * @return the instantiated {@code CaseStyle} * @throws StyleSnifferException if instantiation fails */ @VisibleForTesting CaseStyle instantiateCaseStyle(@NonNull Class clazz) { try { return clazz.getDeclaredConstructor().newInstance(); } catch (InstantiationException e) { throw new StyleSnifferException( String.format("Cannot instantiate case style class %s. Is it abstract?", clazz.getName()), e); } catch (IllegalAccessException | NoSuchMethodException e) { throw new StyleSnifferException( String.format( "Access violation while instantiating case style class %s. Does it has a public no args constructor?", clazz.getName()), e); } catch (InvocationTargetException e) { throw new StyleSnifferException( "Exception thrown by constructor for case style class: " + clazz.getName(), e); } } @Override public Optional getCaseStyle(@Nullable final String name) { return sanitizeInput(name) .flatMap( sanitizedName -> caseStyles.stream().filter(style -> style.matches(sanitizedName)).findFirst()); } @Override public Optional getCaseStyleWithVariantOrName(@Nullable final String variantOrName) { return sanitizeInput(variantOrName) .flatMap( sanitizedName -> caseStyles.stream() .filter( style -> style.getName().equals(sanitizedName) || style.getVariantNames().contains(sanitizedName)) .findFirst()); } /** * Performs basic sanity checks on the input, such as trimming whitespace. * * @param name the input name to sanitize * @return an {@link Optional} containing the sanitized name, or an empty {@link Optional} if the * input is invalid */ private Optional sanitizeInput(@Nullable final String name) { return ofNullable(name).map(String::trim).filter(sanitizedName -> !sanitizedName.isEmpty()); } @Override public Set getSupportedCaseStyles() { return caseStyles.stream().map(CaseStyle::getName).collect(toSet()); } @Override public Set getSupportedCaseStylesIncludingVariants() { return caseStyles.stream().flatMap(style -> style.getVariantNames().stream()).collect(toSet()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy