Джерси игнорируя аннотации Джексона

Этот ответ будет охватывать многие из тех же элементов, что и существующие ответы, но эта проблема (передающая имена столбцов для функций) возникает достаточно часто, и я хочу, чтобы там был ответ, который охватывал вещи немного более всесторонне.

Предположим, что у нас очень простой фрейм данных:

dat <- data.frame(x = 1:4,
                  y = 5:8)

, и мы хотели бы написать функцию, которая создает новый столбец z, который представляет собой сумму столбцов x и y.

Очень распространенный камень преткновения здесь состоит в том, что естественная (но некорректная) попытка часто выглядит так:

foo <- function(df,col_name,col1,col2){
      df$col_name <- df$col1 + df$col2
      df
}

#Call foo() like this:    
foo(dat,z,x,y)

Проблема здесь в том, что df$col1 t оценить выражение col1. Он просто ищет столбец в df, буквально называемый col1. Это поведение описано в ?Extract в разделе «Рекурсивные (похожие на список) объекты».

Самое простое и наиболее часто рекомендуемое решение - это просто переключиться с $ на [[ и передать аргументы функции как строки:

new_column1 <- function(df,col_name,col1,col2){
    #Create new column col_name as sum of col1 and col2
    df[[col_name]] <- df[[col1]] + df[[col2]]
    df
}

> new_column1(dat,"z","x","y")
  x y  z
1 1 5  6
2 2 6  8
3 3 7 10
4 4 8 12

Это часто считается «лучшей практикой», так как это самый сложный метод. Передача имен столбцов в виде строк примерно такая же однозначная, как вы можете получить.

Следующие два варианта более продвинутые. Многие популярные пакеты используют эти методы, но использование их хорошо требует большей осторожности и умения, поскольку они могут вводить тонкие сложности и непредвиденные точки отказа. Этот раздел книги Хэдли Advanced R является отличной ссылкой для некоторых из этих проблем.

Если вы действительно хотите сохранить пользователя от ввода всех этих кавычки, одним из вариантов может быть преобразование голой, некотируемых имен столбцов в строки с помощью deparse(substitute()):

new_column2 <- function(df,col_name,col1,col2){
    col_name <- deparse(substitute(col_name))
    col1 <- deparse(substitute(col1))
    col2 <- deparse(substitute(col2))

    df[[col_name]] <- df[[col1]] + df[[col2]]
    df
}

> new_column2(dat,z,x,y)
  x y  z
1 1 5  6
2 2 6  8
3 3 7 10
4 4 8 12

Это, откровенно говоря, немного глупо, возможно, так как мы действительно делаем то же самое, что и в new_column1, просто с кучей дополнительной работы, чтобы преобразовать простые имена в строки.

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

new_column3 <- function(df,col_name,expr){
    col_name <- deparse(substitute(col_name))
    df[[col_name]] <- eval(substitute(expr),df,parent.frame())
    df
}

Просто для удовольствия я все еще использую deparse(substitute()) для имени нового столбца , Здесь будет работать все следующее:

> new_column3(dat,z,x+y)
  x y  z
1 1 5  6
2 2 6  8
3 3 7 10
4 4 8 12
> new_column3(dat,z,x-y)
  x y  z
1 1 5 -4
2 2 6 -4
3 3 7 -4
4 4 8 -4
> new_column3(dat,z,x*y)
  x y  z
1 1 5  5
2 2 6 12
3 3 7 21
4 4 8 32

Итак, короткий ответ в основном: передать имена столбцов data.frame в виде строк и использовать [[ для выбора отдельных столбцов. Только начинайте разбираться в eval, substitute и т. Д., Если вы действительно знаете, что делаете.

0
задан Alex Malcolm 15 January 2019 в 16:46
поделиться

2 ответа

Решение, которое я нашел для этой проблемы, к сожалению, может не иметь ничего общего с Джексоном или Джерси. Как кто-то сказал: «Это так ненужно, сбивает с толку и затрудняет выяснение того, для чего фактически используется». На мой вопрос я не поделился всей длиной 174 зависимости pom.xml, поэтому никто не смог бы ответить на этот вопрос. Я надеюсь, что кто-то найдет это полезным, хотя.

Когда я добавил @XmlTransient в поле, это не имело положительного значения. Когда я добавил его в геттер и поле, я смог скрыть analyticsActivity от созданного JSON. Я не проверял, насколько эффективно добавление @XmlTransient к одному геттеру.

import javax.xml.bind.annotation.XmlTransient;

@Entity
@Table(name = "PAGE")
@XmlRootElement
public class Page implements Serializable {

    //... Id and other fields here

    @XmlTransient
    @OneToMany(fetch = LAZY, mappedBy = "page")
    private Set<Activity> analyticsActivity;

    @XmlTransient
    public Set<TmptREPDeskAnalytics> getAnalyticsActivity() {
        return analyticsActivity;
    }
}
0
ответ дан Alex Malcolm 15 January 2019 в 16:46
поделиться

Некоторое время назад у меня была та же проблема, аннотация JsonIgnoreProperties используется в области видимости класса. На Джексоне, если вы хотите игнорировать какое-либо поле, вам нужно указать имя поля.

@JsonIgnoreProperties(ignoreUnknown = true, value= {"prev", "next"})
public class Model implements Serializable {
    private Model prev;
    private Model next; ....

Пример игнорирования аннотаций Джексона

Чтобы предотвратить «бесконечную рекурсию (StackOverflowError)», убедитесь, что у вас нет какой-либо ссылки, метода, вызывающего внутренний член, чтобы предотвратить можете игнорировать эти поля тоже. Пример «бесконечной рекурсии (StackOverflowError)»

public class Model implements Serializable {
    private Model prev; // reference previous model
    private Model next; // reference next model

этот тип структуры данных вызывает бесконечную рекурсию, потому что Джексон всегда получает пред или следующее поле и получает снова и снова и снова.

0
ответ дан Gustavo de Souza 15 January 2019 в 16:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: