Подтвердить что ты не робот

Java toString для любого объекта

У меня много объектов данных, и я хочу иметь возможность генерировать String, представляющий каждый объект, без реализации метода toString для каждого из них.

Я думаю об отражении для получения полей и их значений.

любые другие идеи?

спасибо.

4b9b3361

Ответ 1

Вы можете использовать ToStringBuilder из jakarta. Он имеет 2 режима, каждый из которых требует добавления всех полей, которые вам нужны, с использованием API, а другое - на основе отражения:

@Override
public String toString() {
    return ToStringBuilder.reflectionToString(this);
}

Ответ 2

Используйте JUtils для создания метода toString на уровне пакета

Или используя отражение, вы можете попробовать что-то вроде этого:

public static void toString(Object object) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException{
        Class c = object.getClass();
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            if(method.getName().startsWith("get")){
                System.out.println(method.getName()+" -> " +method.invoke(object, null));
            }
        }
    }

Плагин JUtil был бы лучше, потому что это позволит вам позже изменить объект toString объекта, если вам нужно предоставить дополнительную информацию об объекте.

Ответ 3

Если у вас много объектов, вместо добавления toString в каждом классе используйте инструментарий кода (вы можете изменить класс в банках или изменить их в режиме загрузки с помощью javaagent). Например AspectJ поможет, но есть и другие альтернативы. Например, вы можете сделать такую ​​вещь (используя AspectJ и ToStringBuilder из Apache Commons):

@Aspect
public class ToStringAspect {

     @Around("execution(String *.toString()) &&  target(t) && within(your.target.package.*)")
     public String toStringCall(Object t) {
        return ToStringBuilder.reflectionToString(t);
    }
}

ToStringBuilder очень гибкий. например если вам не нужен стиль использования имени класса, установив StandardToStringStyle # setUseClassName (false):

 public String toStringCall(Object t) {
     StandardToStringStyle style = new StandardToStringStyle();
     style.setUseClassName(false);
     style.setUseIdentityHashCode(false);
    ToStringBuilder builder = new ReflectionToStringBuilder(t, style);
    return builder.toString();
}

Ответ 4

Существует несколько способов реализации метода toString.

  • Размышления (библиотека Apache)

    @Override
    public String toString(){
        return org.apache.commons.lang3.builder.ReflectionToStringBuilder.toString(this);
    }
    
  • Реализация на основе JSON (библиотеки GSON, Jackson)

    // GSON library for JSON
    @Override
    public String toString(){
        return new com.google.gson.Gson().toJson(this);
    }
    
    // Jackson libabry for JSON/YAML
    @Override
    public String toString() {
        try {
            return new com.fasterxml.jackson.databind.ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
        } catch (com.fasterxml.jackson.core.JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
    
  • ToStringBuilder (доступен в библиотеке apache-commons)

    @Override
    public String toString() {
        return new org.apache.commons.lang3.builder.ToStringBuilder(this).
            append("field1", field1).
            append("field2", field2).
            toString();
    }
    
  • Выполнение жесткого ядра toString()

    @Override
    public String toString() {
        return new StringBuilder()
            .append("field1:"+field1)
            .append("field2:"+field2)
            .toString();
    }
    

Ответ 5

Метод toString наследуется каждым классом в Java, от java.lang.Object. Я не вижу, как можно избежать реализации (фактически переопределяя) Object.toString. Кроме того, методы определены для каждого класса, а не для каждого объекта.

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

Вы также можете исследовать использование перекодирования байт-кода, если вы вообще не хотите переопределять метод. Лично я не думаю, что усилия, вложенные в плетение байт-кода, не стоят того, особенно когда вы могли бы переопределить toString.

Ответ 6

Может возникнуть какой-то статический метод String dataToString(Data data). У меня нет никакого знания об отражении, так что это моя идея вне этого.

Реализация метода будет зависеть от того, как объекты данных будут настроены. Есть ли наследство? Если это так, вы можете просто передать объект типа суперкласс в качестве параметра и использовать метод глобально для всех данных. Вам нужно будет выполнить некоторую условную проверку или другую форму логики в рамках метода, в зависимости от того, как именно ваша программа настроена, чтобы вернуть правильную строку.

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

Ответ 7

Если вы хотите реализовать toString() для каждого объекта, вы можете использовать AspectJ. Вне чего-то вроде этого вы будете застревать, реализуя метод для каждого объекта.

Ответ 8

Как уже упоминалось, вы можете использовать уже реализованные библиотеки, как ReflectionToStringBuilder от Apache commons-lang. Как уже упоминалось.

Или напишите smt аналогично с помощью API отражения.

Вот пример:

class ReflectionAnalyzer {

   private ArrayList<Object> visited = new ArrayList<Object>();

   /**
    * Converts an object to a string representation that lists all fields.
    * @param obj an object
    * @return a string with the object class name and all field names and
    * values
    */
   public String toString(Object obj) {
      if (obj == null) return "null";
      if (visited.contains(obj)) return "...";
      visited.add(obj);
      Class cl = obj.getClass();
      if (cl == String.class) return (String) obj;
      if (cl.isArray()) {
         String r = cl.getComponentType() + "[]{";
         for (int i = 0; i < Array.getLength(obj); i++) {
            if (i > 0) r += ",";
            Object val = Array.get(obj, i);
            if (cl.getComponentType().isPrimitive()) r += val;
            else r += toString(val);
         }
         return r + "}";
      }

      String r = cl.getName();
      // inspect the fields of this class and all superclasses
      do {
         r += "[";
         Field[] fields = cl.getDeclaredFields();
         AccessibleObject.setAccessible(fields, true);
         // get the names and values of all fields
         for (Field f : fields) {
            if (!Modifier.isStatic(f.getModifiers())) {
               if (!r.endsWith("[")) r += ",";
               r += f.getName() + "=";
               try {
                  Class t = f.getType();
                  Object val = f.get(obj);
                  if (t.isPrimitive()) r += val;
                  else r += toString(val);
               } catch (Exception e) {
                  e.printStackTrace();
               }
            }
         }
         r += "]";
         cl = cl.getSuperclass();
      } while (cl != null);

      return r;
   }    
}