كيف يمكنني الرجوع إلى واجهات برمجة التطبيقات Java 1.6 أثناء التحف بأمان ضد Java 1.5؟

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

  •  16-09-2019
  •  | 
  •  

سؤال

أود استخدام java.text.normalizer. فئة من Java 1.6 للقيام بتطبيع Unicode، ولكن يجب أن يكون التعليمات البرمجية قادرا على تشغيل Java 1.5.

لا مانع إذا كان الرمز الذي يعمل على 1.5 لا يقوم بالتطبيع، لكنني لا أريد ذلك NoClassDefFoundErrorS أو ClassNotFoundExceptionS عندما يعمل.

ما هي أفضل طريقة لتحقيق ذلك؟

هل كانت مفيدة؟

المحلول

الطريقة المعتادة للقيام بذلك عن طريق الانعكاس، أي لا تشير مباشرة إلى الفصل المعني، ولكن استدعاءها برمجيا. هذا يسمح لك بالقبض على الاستثناءات بأمان إذا لم يكن الرمز المعني، وإما يتجاهله، أو جرب شيئا آخر. رميات انعكاس 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 لا يقوم بالتطبيع، لكنني لا أريد ذلك إعطاء NoclassDeffoundrorrorrorrors أو expressionstextextions عند تشغيله.

إذا كنت ترغب في تجنب الانعكاس، فيمكنك بالفعل التقاط هذه الأخطاء.

بهذه الطريقة، يمكنك تجميعها مقابل الطبقات الجديدة اللامعة مع مترجم JAVA6، وسوف لا تزال تعمل (كما في "لا تفعل أي شيء، ولكن أيضا لا تعطل") على Java5.

يمكنك أيضا الجمع بين النهجين، وتحقق مما إذا كان الفصل موجود استخدام التفكير، وإذا استمر في الاتصال به بطريقة غير عكسية. هذا ما يفعله حل أندرو.

إذا كنت بحاجة أيضا إلى ترجمة على Java5، فأنت بحاجة إلى الانعكاس على طول الطريق.

لقد واجهت هذه الحاجة نفسها، حيث أن لدينا رمز يحتاج إلى تشغيل جميع إصدارات Java من Java 1.2، ولكن يحتاج بعض التعليمات البرمجية إلى الاستفادة من API الأحدث إذا كانت متوفرة.

بعد عمليات التباديل المختلفة باستخدام التفكير للحصول على كائنات طريقة وإذارها بشكل حيوي، لقد استقرت في نهج نمط التفاف كأفضل، بشكل عام (على الرغم من أنه في بعض الحالات، فقط تخزين الطريقة المنعكسة كثبات، فإنه يعتمد على ذلك) وبعد

فيما يلي فئة مثال على "فائدة النظام" التي تعرض بعض API الأحدث ل Java 5 عند تشغيل إصدار سابق - نفس المبادئ تحمل Java 6 في JVMS السابقة. يستخدم هذا المثال Singleton، ولكن يمكن بسهولة إنشاء كائنات متعددة إذا كان API الأساسي يحتاج إلى ذلك.

هناك فئتين:

  • sysutil.
  • sysutil_j5.

هذا الأخير هو واحد المستخدم إذا كان JVM وقت التشغيل هو Java 5 أو إصدار أحدث. يتم استخدام طرق الأسطوانة الأخرى المتوافقة في العقد من التنفيذ الافتراضي في SYSUTIL والتي تستخدم فقط Java 4 أو تطبيقات برمجة التطبيقات السابقة. يتم تجميع كل فئة مع مترجم الإصدار المحدد، بحيث لا يوجد استخدام عرضي ل API Java 5+ في فئة Java 4:

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 (جمعت مع مترجم جافا 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 (إذا تم تجميعها باستخدام توافق "utarget" المناسب) أو جافا 6 أو أي إصدار مستقبل آخر.

IMHO هذا يحل مشكلتك بالكامل - أنت حر في الترجمة على أي منصة Java 5+، وأنت قادر على الحصول على الوظيفة المطلوبة (التطبيع) على أي منصة Java 5+ (*)

(*) فإن حل Sun Java 5 للتطبيع لن يكون على الأرجح غير موجود على جميع تطبيقات Java 5، لذلك في أسوأ حالة سيناريو، سينتهي بك الأمر إلى الحصول على طريقة ClassnotfoundException عند استدعاء طريقة GetnormalizationStringFilter ().

    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 الخاص بك حتى تتمكن من مشاركة مشروعك مع المكتبة ويجب أن تكون جافا مستقلة.
العيب هو أن مكتبة وحدة العناية المركزة كبيرة جدا.

إذا كنت تستخدم فئة Normalizer فقط لإزالة اللجهات / التشكيل من السلاسل، فهناك أيضا طريقة أخرى. يمكنك استخدام مكتبة اباتشي المشاع Lang (ver. 3) يحتوي على StringUtils مع طريقة stripAccents():

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

ربما تستخدم Lang3 Library التفكير لاستدعاء Norksizer المناسب وفقا لإصدار Java. ميزة ما هو عدم وجود فوضى انعكاس في التعليمات البرمجية الخاصة بك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top