Насколько безопасный мой безопасный перебросок?

Вот простой метод для удаления XML. Он обрабатывает предопределенные сущности XML и десятичные числовые сущности (& amp; #nnnn;). Его изменение для обработки шестнадцатеричных сущностей (& amp; #xhhhh;) должно быть простым.

public static String unescapeXML( final String xml )
{
    Pattern xmlEntityRegex = Pattern.compile( "&(#?)([^;]+);" );
    //Unfortunately, Matcher requires a StringBuffer instead of a StringBuilder
    StringBuffer unescapedOutput = new StringBuffer( xml.length() );

    Matcher m = xmlEntityRegex.matcher( xml );
    Map<String,String> builtinEntities = null;
    String entity;
    String hashmark;
    String ent;
    int code;
    while ( m.find() ) {
        ent = m.group(2);
        hashmark = m.group(1);
        if ( (hashmark != null) && (hashmark.length() > 0) ) {
            code = Integer.parseInt( ent );
            entity = Character.toString( (char) code );
        } else {
            //must be a non-numerical entity
            if ( builtinEntities == null ) {
                builtinEntities = buildBuiltinXMLEntityMap();
            }
            entity = builtinEntities.get( ent );
            if ( entity == null ) {
                //not a known entity - ignore it
                entity = "&" + ent + ';';
            }
        }
        m.appendReplacement( unescapedOutput, entity );
    }
    m.appendTail( unescapedOutput );

    return unescapedOutput.toString();
}

private static Map<String,String> buildBuiltinXMLEntityMap()
{
    Map<String,String> entities = new HashMap<String,String>(10);
    entities.put( "lt", "<" );
    entities.put( "gt", ">" );
    entities.put( "amp", "&" );
    entities.put( "apos", "'" );
    entities.put( "quot", "\"" );
    return entities;
}
11
задан Bill the Lizard 28 July 2012 в 00:42
поделиться

3 ответа

Есть несколько способов справиться с этим. Первый вариант - мое предпочтение, если вам не нужно знать, что это за исключение.

boolean okay = false;
try {
  // do some work which might throw an exception
  okay = true;
} finally {
  if (!okay) // do some clean up.
}

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

Второй вариант - это взломать, но тоже работает.

try {
    // do some work which might throw an exception
} catch (Throwable t) {
    // do something with t.
    Thread.currentThread().stop(t);
}

Метод stop (Throwable t) не останавливает поток, вместо этого он заставляет поток генерировать исключение, предоставленное неконтролируемым способом.

Вы можете использовать Unsafe.throwException () с немного возиться, и есть способ сделать это с помощью Generics, о котором я забыл.

5
ответ дан 3 December 2019 в 11:04
поделиться

Если вы обеспокоены тем, что произойдет неинициализация, тогда вы можете просто поместить этот код в блок finally, как если бы он должен был быть вызван в какой-то момент, тогда вам, возможно, следует всегда убирать.

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

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

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

1
ответ дан 3 December 2019 в 11:04
поделиться

Альтернативой является наличие фабрики, которая создает SomeException только в том случае, если причиной является проверенное исключение:

   public static SomeException throwException(String message, Throwable cause) throws SomeException {
      unchecked(cause); //calls the method you defined in the question.
      throw new SomeException(message, cause);
   }

Я ввел возвращаемое значение в метод, чтобы клиент мог сделайте что-нибудь вроде этого:

     catch (Throwable e) {
         undoInitialize();
         throw SomeException.throwException("message", e);
     }

, чтобы обмануть компилятор и заставить его не требовать возврата после оператора catch, если метод имеет тип возврата, но он по-прежнему генерирует исключение, если клиент забыл поместить бросок перед вызовом метода factory метод.

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

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

      public SomeException(message, cause) {
            super(message, unchecked(cause));
      }

      private static Throwable unchecked(Throwable cause) {
          if (cause instanceof Error) throw (Error) cause;
          if (cause instanceof RuntimeException) throw (RuntimeException) cause;
          return cause;
      }
1
ответ дан 3 December 2019 в 11:04
поделиться
Другие вопросы по тегам:

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