Java 1.5에 대해 우아하게 저하하면서 Java 1.6 API를 참조하려면 어떻게해야합니까?

StackOverflow https://stackoverflow.com/questions/1277270

  •  16-09-2019
  •  | 
  •  

문제

사용하고 싶습니다 java.text.normalizer Java 1.6에서 유니 코드 정규화를 수행하려면 Class는 코드를 Java 1.5에서 실행할 수 있어야합니다.

1.5에서 실행되는 코드가 정규화되지 않더라도 신경 쓰지 않지만주는 것을 원하지 않습니다. NoClassDefFoundErrors 또는 ClassNotFoundException실행될 때.

이것을 달성하는 가장 좋은 방법은 무엇입니까?

도움이 되었습니까?

해결책

이 작업을 수행하는 일반적인 방법은 반사를 통한 것입니다. 즉, 해당 클래스를 직접 언급하지 않고 프로그래밍 방식으로 호출합니다. 이를 통해 해당 코드가 존재하지 않는 경우 예외를 우아하게 포착 할 수 있습니다. 반사가 던져집니다 ClassNotFoundException, 이것은 좋은 정상적인 예외입니다. NoClassDefFoundError, 그것은 조금 더 무서운 것입니다.

의 경우 java.text.Normalizer, 그것은 몇 가지 정적 방법이기 때문에 반사를 통해 쉽게 호출하기 쉽기 때문에 이것은 매우 쉬워야합니다.

다른 팁

public interface NfcNormalizer
{
  public String normalize(String str);
}

public class IdentityNfcNormalizer implements NfcNormalizer
{
  public String normalize(String str)
  {
    return str;
  }
}

public class JDK16NfcNormalizer implements NfcNormalizer
{
  public String normalize(String str)
  {
    return Normalizer.normalize(str, Normalizer.Form.NFC);
  }
}

클라이언트 코드에서 :

NfcNormalizer normalizer;
try
{
  normalizer = Class.forName("JDK16NfcNormalizer").newInstance();
}
catch(Exception e)
{
  normalizer = new IdentityNfcNormalizer();
}

1.5에서 실행되는 코드가 정규화되지 않더라도 신경 쓰지 않지만 실행될 때 NoclassDeffoundErrors 또는 ClassNotFoundExceptions를 제공하는 것을 원하지 않습니다.

반사를 피하려면 실제로 이러한 오류를 포착 할 수 있습니다.

이런 식으로, 당신은 Java6 컴파일러로 반짝이는 새로운 클래스를 컴파일 할 수 있으며, Java5에서 여전히 "아무것도하지 않고 충돌하지 않는 것처럼"여전히 작동합니다.

또한 두 가지 접근 방식을 결합하고 반사를 사용하여 클래스가 존재하는지 확인하고 반사적이지 않은 방식으로 계속 호출되는지 확인할 수 있습니다. 이것이 앤드류의 해결책이하는 일입니다.

당신도 필요하다면 엮다 Java5에서는 계속 반사해야합니다.

Java 1.2의 모든 버전의 Java에서 실행 해야하는 코드가 있기 때문에 동일한 요구가 있었지만 일부 코드는 사용 가능한 최신 API를 활용해야합니다.

반사를 사용하여 메소드 객체를 얻고 동적으로 호출 한 후, 나는 일반적으로 래퍼 스타일 접근 방식을 최대한 활용했습니다 (일부 상황에서는 반사 된 방법을 정적으로 저장하고 호출하는 것이 더 좋습니다). .

다음은 이전 버전을 실행할 때 Java 5 용 특정 최신 API를 노출시키는 "System Utility"클래스의 예입니다. 이전 JVMS에서 Java 6에 대해 동일한 원칙이 유지됩니다. 이 예제는 싱글 톤을 사용하지만 기본 API에 필요한 경우 여러 객체를 쉽게 인스턴스화 할 수 있습니다.

두 가지 클래스가 있습니다.

  • Sysutil
  • sysutil_j5

후자는 런타임 JVM이 Java 5 이상인 경우 사용되는 것입니다. 그렇지 않으면 계약에서 호환되는 폴백 방법은 Java 4 이상의 API 만 사용하는 Sysutil의 기본 구현에서 사용됩니다. 각 클래스는 특정 버전의 컴파일러로 컴파일되므로 Java 4 클래스에서 Java 5+ API를 우연히 사용하지 않습니다.

Sysutil (Java 4 컴파일러로 컴파일)

import java.io.*;
import java.util.*;

/**
 * Masks direct use of select system methods to allow transparent use of facilities only
 * available in Java 5+ JVM.
 *
 * Threading Design : [ ] Single Threaded  [x] Threadsafe  [ ] Immutable  [ ] Isolated
 */

public class SysUtil
extends Object
{

/** Package protected to allow subclass SysUtil_J5 to invoke it. */
SysUtil() {
    super();
    }

// *****************************************************************************
// INSTANCE METHODS - SUBCLASS OVERRIDE REQUIRED
// *****************************************************************************

/** Package protected to allow subclass SysUtil_J5 to override it. */
int availableProcessors() {
    return 1;
    }

/** Package protected to allow subclass SysUtil_J5 to override it. */
long milliTime() {
    return System.currentTimeMillis();
    }

/** Package protected to allow subclass SysUtil_J5 to override it. */
long nanoTime() {
    return (System.currentTimeMillis()*1000000L);
    }

// *****************************************************************************
// STATIC PROPERTIES
// *****************************************************************************

static private final SysUtil            INSTANCE;
static {
    SysUtil                             instance=null;

    try                  { instance=(SysUtil)Class.forName("SysUtil_J5").newInstance(); } // can't use new SysUtil_J5() - compiler reports "class file has wrong version 49.0, should be 47.0"
    catch(Throwable thr) { instance=new SysUtil();                                                                    }
    INSTANCE=instance;
    }

// *****************************************************************************
// STATIC METHODS
// *****************************************************************************

/**
 * Returns the number of processors available to the Java virtual machine.
 * <p>
 * This value may change during a particular invocation of the virtual machine. Applications that are sensitive to the
 * number of available processors should therefore occasionally poll this property and adjust their resource usage
 * appropriately.
 */
static public int getAvailableProcessors() {
    return INSTANCE.availableProcessors();
    }

/**
 * Returns the current time in milliseconds.
 * <p>
 * Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the
 * underlying operating system and may be larger. For example, many operating systems measure time in units of tens of
 * milliseconds.
 * <p>
 * See the description of the class Date for a discussion of slight discrepancies that may arise between "computer time"
 * and coordinated universal time (UTC).
 * <p>
 * @return         The difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
 */
static public long getMilliTime() {
    return INSTANCE.milliTime();
    }

/**
 * Returns the current value of the most precise available system timer, in nanoseconds.
 * <p>
 * This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock
 * time. The value returned represents nanoseconds since some fixed but arbitrary time (perhaps in the future, so values
 * may be negative). This method provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees
 * are made about how frequently values change. Differences in successive calls that span greater than approximately 292
 * years (263 nanoseconds) will not accurately compute elapsed time due to numerical overflow.
 * <p>
 * For example, to measure how long some code takes to execute:
 * <p><pre>
 *    long startTime = SysUtil.getNanoTime();
 *    // ... the code being measured ...
 *    long estimatedTime = SysUtil.getNanoTime() - startTime;
 * </pre>
 * <p>
 * @return          The current value of the system timer, in nanoseconds.
 */
static public long getNanoTime() {
    return INSTANCE.nanoTime();
    }

} // END PUBLIC CLASS

sysutil_j5 (Java 5 컴파일러로 컴파일)

import java.util.*;

class SysUtil_J5
extends SysUtil
{

private final Runtime                   runtime;

SysUtil_J5() {
    super();

    runtime=Runtime.getRuntime();
    }

// *****************************************************************************
// INSTANCE METHODS
// *****************************************************************************

int availableProcessors() {
    return runtime.availableProcessors();
    }

long milliTime() {
    return System.currentTimeMillis();
    }

long nanoTime() {
    return System.nanoTime();
    }

} // END PUBLIC CLASS

클래스를 확인/사용/수정합니다 info.olteanu.utils.textnormalizer Phramer 프로젝트에서 (http://sourceforge.net/projects/phramer/ , www.phramer.org) - 코드는 BSD 라이센스가 부여되었습니다.

이 코드는 Java 5에서 컴파일 될 수 있으며 Java 5 또는 Java 6 (또는 미래의 Java 버전) 모두에서 실행할 수 있습니다. 또한 Java 6에서 컴파일되어 Java 5 (바이트 코드 호환성을 위해 적절한 "-타겟"으로 컴파일 된 경우) 또는 Java 6 또는 기타 미래 버전에서 실행할 수 있습니다.

IMHO 이것은 문제를 완전히 해결합니다. Java 5+ 플랫폼에서 자유롭게 컴파일 할 수 있으며 Java 5+ 플랫폼 (*)에서 원하는 기능 (정규화)을 얻을 수 있습니다.

(*) 정규화를위한 Sun Java 5 솔루션은 모든 Java 5 구현에 존재하지 않을 가능성이 높으므로 최악의 시나리오에서는 getNormalizationStringFilter () 메소드를 호출 할 때 ClassNotFoundException을 얻게됩니다.

    String str = "éèà";
    try {
        Class c = Class.forName("java.text.Normalizer");
        Class f = Class.forName("java.text.Normalizer$Form");
        Field ff = f.getField("NFD");
        Method m = c.getDeclaredMethod("normalize", new Class[]{java.lang.CharSequence.class,f});
        temp = (String) m.invoke(null, new Object[]{str,ff.get(null)});
    } catch (Throwable e) {
        System.err.println("Unsupported Normalisation method (jvm <1.6)");
    }
    System.out.println(temp+" should produce [eea]");

이것은 오래된 질문이지만 여전히 실제입니다. 나는 답에 언급되지 않은 몇 가지 가능성을 알았습니다.

일반적으로 다른 답변에 표시된대로 반사를 사용하는 것이 좋습니다. 그러나 코드에 혼란을 입히고 싶지 않다면 사용할 수 있습니다. ICU4J 라이브러리. 그것은 포함되어 있습니다 com.ibm.icu.text.Normalizer 수업 normalize() java.text.normalizer/sun.text.normalizer와 동일한 작업을 수행하는 메소드. ICU 라이브러리에는 Normalizer의 구현이 있어야하므로 프로젝트를 라이브러리와 공유 할 수 있으며 이는 Java 독립적이어야합니다.
단점은 ICU 라이브러리가 상당히 크다는 것입니다.

문자열에서 악센트/디아크리닉을 제거하기 위해 Normalizer 클래스를 사용하는 경우 다른 방법도 있습니다. 당신이 사용할 수있는 Apache Commons Lang Library (Ver. 3) 그것은 포함되어 있습니다 StringUtils 방법으로 stripAccents():

String noAccentsString = org.apache.commons.lang3.StringUtils.stripAccents(s);

LANG3 라이브러리는 아마도 반사를 사용하여 Java 버전에 따라 적절한 정규화를 호출 할 수 있습니다. 따라서 이점은 코드에 반사 혼란이 없다는 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top