Передать метод и аргументы функции в Java - PullRequest
2 голосов
/ 05 мая 2020

Итак, я выполняю простую операцию поиска записи в моем репозитории. Если запись отсутствует, генерируется исключение.

@NotNull
public static User getUserFromUuid(UUID userUuid) {
    Optional<User> userOptional = userRepository.findByUserIdentifier(userUuid);
    if (!userOptional.isPresent()) {
        if (logger.isInfoEnabled()) logger.info(String.format("Unable to find user with uuid %s", userUuid.toString()));
        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User Not Found");
    }
    return userOptional.get();
}
@NotNull
public static Group getGroupFromId(Long groupId) {
    Optional<Group> groupOptional = groupRepository.findById(groupId);
    if (!groupOptional.isPresent()) {
        if (logger.isInfoEnabled()) logger.info(String.format("Group with id %s does not exist", groupId));
        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Group Not Found");
    }
    return groupOptional.get();
}

Я понимаю, что в конечном итоге проделал бы это много раз для всех моих методов поиска. И большинство из них будут выполнять очень похожую задачу.

Один из способов - расширить CrudRepository моей версией, но я хочу реализовать этот шаблон для всех находками.

Другой способ - передать класс, метод, параметры и сообщение об ошибке для поиска. Лямбда-метод кажется подходящим, но я не мог понять, как я могу применить его к моей проблеме.

Этот приближается к решению проблемы, но тип возвращаемого значения меняется. Я бы также передавал переменное количество аргументов.

Есть ли какой-нибудь подход, который я могу предпринять для этого?

EDIT:

Я также хотел бы заняться этим делом

Optional<GroupUser> groupUser = groupUserRepository.findByUserAndGroup(user, group

Где я может иметь более одного параметра поиска.

Что-то подобное в python будет

def perform( fun, *args ):
    fun( *args )

def action1( args ):
    something

def action2( args ):
    something

perform( action1 )
perform( action2, p )
perform( action3, p, r )

Ответы [ 3 ]

1 голос
/ 05 мая 2020

Поскольку все ваши значения могут быть представлены строкой, вы можете сделать следующее:

public static Object getAccountDetails(String primaryKey, Class<?> targetClass) {   
        Optional<?> result;

        switch(targetClass.getSimpleName())
        {
        case "Group":
             result = Test.dummyFind(primaryKey);
             break;
        case "User":
            result =  Test.dummyFind(primaryKey);
            break;
        default:
            throw new IllegalArgumentException("The provided class: "+targetClass.getCanonicalName()+" was not a valid class to be resolved by this method.");      
        }

        if(result.isPresent())
        {
            logger.info(String.format("Group with id %s does not exist", groupId));
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Group Not Found"); 
        }

        return result.get();
    }

Насколько мне известно, нет необходимости проверять, включен ли в регистраторе уровень информации, поскольку это определяется вашей конфигурацией входа в систему. Поэтому, если нет записи в журнал для информации, она не будет зарегистрирована.

Использование функции будет примерно таким (классы случайны, так как я хотел выделить подсветку синтаксиса):

UserDataHandler data = (UserDataHandler) getAccountDetails("1234", UserDataHandler.class);

Это не зависит от какой-либо функциональности Spring, поскольку я с ней не работаю. <?> - оператор с подстановочным знаком. Поскольку ваш результат, однако, является содержимым Optional, вы должны вернуть Object, который затем должен быть проанализирован в соответствии с типом.

Двумя способами: Либо вы используете такой реестр:

public static Object getAccountDetails(Object primaryKey, Class<?> targetClass) {   

    Optional<?> result;

    // This map should be acquired from a Singleton where you register these classes once in @PostConstruct.
    Map<String, Method> methodMap = new TreeMap<>();
    try {
        methodMap.put("UserDataHandler", Test.class.getMethod("dummyFind"));
    } catch (NoSuchMethodException | SecurityException e) {}


    if(methodMap.containsKey(targetClass.getName()))
    {
        Method method = methodMap.get(targetClass.getName());
        try {
            result = (Optional<?>) method.invoke(primaryKey);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            // do some more error handling
            return null;
        }
    }
    else throw new IllegalArgumentException("The provided class: "+targetClass.getCanonicalName()+" was not a valid class to be resolved by this method.");


    if(!result.isPresent())
    {
        logger.info(String.format("Group with id %s does not exist", groupId));
        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Group Not Found"); 
    }

    return result.get();
}

или даже более умный метод - просто всегда называть методы в одном и том же шаблоне, чтобы любой получал целевой репозиторий Class.forName(String):

public static Object getAccountDetails(Object primaryKey, Class<?> targetClass) {   

    Optional<?> result;

    Class<?> myRepository = Class.forName(targetClass.getSimpleName()+"Repository");

    String methodName = "findBy"+targetClass.getName();

    try
    {
        Method findMethod = targetClass.getMethod(methodName);
        result = (Optional<?>) findMethod.invoke(primaryKey);
    }
    catch (NoSuchMethodException e){throw new IllegalArgumentException("The method "+methodName+" couldn't be found in the repository");}
    catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {return null;}


    if(!result.isPresent())
    {
        logger.info(String.format("Group with id %s does not exist", groupId));
        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Group Not Found"); 
    }

    return result.get();
}

Для обоих методов ваша функция поиска должна принимать Объект как аргумент, который должен быть приведен, чтобы использовать его:

public static Optional<Long> dummyFind(Object primaryKey)
{
    long typedPrimaryKey = (long) primaryKey;
    return Optional.of(typedPrimaryKey);
}

Но, поскольку я подумал об этом дважды, все, что вы хотите, уже существует: EntityManager.find(Class<T> entityClass,Object primaryKey)

1 голос
/ 05 мая 2020

Вы можете создать общий метод c, который принимает Optional любого типа и строки для сообщения журнала. Он вернет объект, если он присутствует, иначе будет исключение

public <T> T returnIfPresent(Optional<T> optional, String id){

    if (!optional.isPresent()) {
        if (logger.isInfoEnabled()) logger.info(String.format("Group with id %s does not exist", id));
        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Group Not Found");
    }
    return optional.get();
}

И вы можете вызвать этот метод из любого метода

@NotNull
public static User getUserFromUuid(UUID userUuid) {

    Optional<User> userOptional = userRepository.findByUserIdentifier(userUuid);
    return returnIfPresent(userOptional, userUuid.toString());
 }

 @NotNull
 public static Group getGroupFromId(Long groupId) {
     Optional<Group> groupOptional = groupRepository.findById(groupId);

     return returnIfPresent(groupOptional, groupId.toString());
 }

Еще одно предложение, которое я бы рекомендовал, - наличие сообщения в качестве второго параметра, чтобы вы могли создать сообщение исходным методом и передать его через

public <T> T returnIfPresent(Optional<T> optional, String message){

    if (!optional.isPresent()) {
        if (logger.isInfoEnabled()) logger.info(message);
        throw new ResponseStatusException(HttpStatus.NOT_FOUND, message);
    }
    return optional.get();
}
1 голос
/ 05 мая 2020

Вы ищете что-то подобное?

public static <T, ID>  T process(Class<T> cls, CrudRepository<T,ID> r, ID id, String errTemplate){
    Optional<T> groupOptional = r.findById(id);
    if (groupOptional.isEmpty()) {
        if (logger.isInfoEnabled()) logger.info(String.format(errTemplate, id));
        throw new ResponseStatusException(HttpStatus.NOT_FOUND, cls.getName() + " Not Found");
    }
    return groupOptional.get();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...