Статьи

Хорошо, все, кто касается байт-кода Java

Oracle v. Google считает, что копирование структуры, последовательности и организации API-интерфейсов Java является нарушением авторских прав. Нарушение авторских прав — это не только акт копирования, но и все промежуточные стороны, у которых есть копия произведения.

Это любой, кто пишет / компилирует любой язык JVM, и любой, у кого есть файл JAR на любом устройстве, которое у них есть… включая апплет Java ME на вашем старом раскладном телефоне Motorola. Фактически, JVM во всех ее воплощениях настолько распространен, что, вероятно, у каждого взрослого в каждой промышленно развитой стране есть какая-то JVM, работающая где-то.

И каждый JAR-файл, не относящийся к Sun / Oracle, имеет встроенную копию некоторых или всех API Java, потому что технически необходимо включить тень API в скомпилированный байт-код для вызова API.

Позвольте мне продемонстрировать.

Вот совершенно легальная Java-программа, на которую я написал, и мне принадлежат авторские права:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
public class HelloWorld {
 
    public static void main(String[] args) {
    int strlen = 0;
 
    for (int x = 0; x < args.length; x++) {
        strlen += args[x].length();
    }
 
    System.out.println("Hello, world, you passed in "+args.length+" arguments, "+
               "total size: "+strlen);
    }
 
}

Ничто там не выглядит нарушающим. Я запускаю программу через Java-компилятор OpenJDK, javac который приводит к файлу HelloWorld.class . В соответствии с тем, как в отрасли используются Java и компиляторы в целом, полученный байт-код является производной от исходного кода, и мне принадлежат авторские права на исходный код.

Итак, давайте посмотрим на полученный байт-код, разобранный с помощью javap :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
dpp@crown:~/proj/dpp-blog/images$ javap -c HelloWorld
Compiled from "HelloWorld.java"
public class HelloWorld {
  public HelloWorld();
    Code:
       0: aload_0      
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return       
 
  public static void main(java.lang.String[]);
    Code:
       0: iconst_0     
       1: istore_1     
       2: iconst_0     
       3: istore_2     
       4: iload_2      
       5: aload_0      
       6: arraylength  
       7: if_icmpge     25
      10: iload_1      
      11: aload_0      
      12: iload_2      
      13: aaload       
      14: invokevirtual #2                  // Method java/lang/String.length:()I
      17: iadd         
      18: istore_1     
      19: iinc          2, 1
      22: goto          4
      25: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      28: new           #4                  // class java/lang/StringBuilder
      31: dup          
      32: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
      35: ldc           #6                  // String Hello, world, you passed in
      37: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      40: aload_0      
      41: arraylength  
      42: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      45: ldc           #9                  // String  arguments,
      47: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      50: ldc           #10                 // String total size:
      52: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      55: iload_1      
      56: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      59: invokevirtual #11                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      62: invokevirtual #12                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      65: return       
}

О, мой… послушайте, некоторые из API Java проникли прямо в код.

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

Таким образом, каждый скомпилированный JAR содержит некоторую часть встроенного в него Java API. Каждый скомпилированный файл JAR является нарушением авторских прав по решению Oracle.

«Но, — говорите вы, — файл JAR не содержит всех спорных API».

Во-первых, сколько достаточно. Суд Oracle явно отклонил аргумент о том, что API-интерфейсы были небольшой частью общей работы базовых классов Java, и что аргументы в процентах не были убедительными.

Во-вторых, для таких репозиториев, как Maven Central , в которых хранятся десятки тысяч файлов JAR, практически все API-интерфейсы Java копируются в коллективные произведения, которые размещены в этих файлах JAR.

Что делать?

Если бы я размещал тонну JAR-файлов, я бы позвонил своим адвокатам, пытаясь выяснить, что делать. Да, может быть, есть побудительный аргумент, потому что Oracle распространяет javac и поэтому побуждает меня копировать API Java. Но все же, это техническое нарушение решения суда Oracle.

Если бы я был Apache Software Foundation или Free Software Foundation, я бы сегодня утром подал бы ходатайство ex parte, чтобы получить отсрочку решения Oracle, потому что это означает, что мы думаем, что наше программное обеспечение, на которое мы можем лицензировать наши открытые условия на самом деле содержат защищенный авторским правом код Oracle, и нам придется приостановить все наши связанные с JVM проекты с открытым исходным кодом.

Да, и я должен отметить, что если Oracle заявляет, что API, скопированные в файлы JAR, не защищены авторским правом, то все, что нужно сделать Google, это извлечь все файлы JAR из Maven Central, найти все ссылки на API Java во всех этих JAR-файлы и использовать эту информацию для объявления API для Android. Это максимум 10 человеко-дней усилий.

Ссылка: Хорошо, все, кто касается байт-кода Java от нашего партнера JCG Дэвида Поллака в блоге DPP в блоге.