Postgres PL/JAVA: ошибка java.lang.ClassNotFoundException после загрузки файла JAR в базу данных

Я получаю исключение java.lang.ClassNotFoundException: ошибка внутри Postgres при запуске функции, которая вызывает загруженный файл JAR. Я установил и сконфигурировал PL/JAVA (включая предоставленные примеры) в своей базе данных и могу запустить примеры к успеху. Я не пытаюсь загрузить / установить свой первый JAR, но я делаю что-то не так.

Мой хост контролирует версию ОС: CentOS 6.8. Postgres - это версия 8.4.

Я пытаюсь установить свой собственный очень простой Java-класс, который является производным от предоставленного примера класса Parameters.addOne. Весь мой код находится в /tmp. Вот шаги, которые я выполнил:

Doug.java:

    package com.msmetric;
    import java.math.BigDecimal;
    import java.sql.Date;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Time;
    import java.sql.Timestamp;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.TimeZone;
    import java.util.logging.Logger;

    public class Doug {
      public static int addOne(int value) {
        return value + 1;
       }
    }
  1. Скомпилируйте Doug.java, используя 'javac Doug.java'.

  2. Создайте файл JAR с файлом Doug.class, используя 'jar -cvf Doug.jar Doug.class. Это отлично работает.

Теперь я загружаю файл JAR в Postgres (общедоступную схему), изменяю classpath, создаю функцию, которая вызывает JAR, а затем пытаюсь запустить в приглашении psql.

  1. Запустите sqlj.install_jar из psql:

    select sqlj.install_jar('file:/tmp/Doug.jar','Doug',false);
    
  2. Задайте путь к классам внутри Postgres (из приглашения psql postgres=#):

    select sqlj.set_classpath('public','Doug');
    
  3. Создайте функцию, которая вызывает JAR. Этот код функции создания взят непосредственно из файла examples.ddr, поставляемого с PL/JAVA. Я просто изменил org.postgres на com.msmetric.

    create or replace function addone(int) returns int as 'com.msmetric.Doug.addOne(java.lang.Integer)' language java;
    

Теперь с загруженным JAR и созданной функцией я пытаюсь запустить его. Эта функция должна просто добавить 1 к предоставленному номеру.

    select addone(3);

Результаты: ОШИБКА: java.lang.ClassNotFoundException: com.msmetric.Doug

Мысли?

1 ответ

Мне очень жаль, что я не увидела ваш вопрос раньше. Под всеми экзотическими деталями (PostgreSQL, PL/Java, схемы, пути к классам...), здесь происходит лишь немного базовой Java: если файл jar содержит класс Doug.class в упаковке com.msmetric его путь внутри банки должен отражать это: он должен быть com/msmetric/Doug.class, В противном случае он не будет найден.

Вы можете настроить всю эту структуру шаг за шагом:

javac Doug.java mkdir com mkdir com/msmetric mv Doug.class com/msmetric/ jar -cvf Doug.jar com/msmetric/Doug.class

Или вы можете позволить javac сделать больше работы для вас:

mkdir classes javac -d classes Doug.java jar -cvf Doug.jar -C classes .

Когда вы даете javac -d опция каталога, а не просто запись файлов классов рядом с их .java Источники, он поместит их все на свои места в каталоге, который вы назвали, а затем вы можете просто сказать jar переместиться в этот каталог и вылить их все на стол (не забывайте . в конце этого jar команда).

Как только вы исправите это, если вы попытаетесь повторить свои первоначальные шаги, вы увидите, что теперь вы получите другую ошибку:

ERROR:  Unable to find static method com.msmetric.Doug.addOne with signature (Ljava/lang/Integer;)I

Это происходит потому, что вы объявили функцию в Doug.java с int addOne(int value) (то есть, принимая примитив int аргумент), но вы объявили это в SQL с returns int as 'com.msmetric.Doug.addOne(java.lang.Integer)' принимая Integer объект.

Как только вы исправите это:

create or replace function addone(int) returns int as 'com.msmetric.Doug.addOne(int)' language java;

вы сможете увидеть:

# select addone(3);
 addone 
--------
      4
(1 row)

Если вам посчастливилось увидеть этот запоздалый ответ, могу я спросить, какую версию PL / Java вы используете? Это одна деталь, которую вы не упомянули. Если он старше 1.5.0, есть новые функции, которые могут вам помочь. Например, вы можете просто аннотировать эту функцию:

@Function
public static int addOne(int value) {
  return value + 1;
}

и имеют javac выплюнуть не только Doug.class файл, но и pljava.ddr файл с вашей декларацией функции SQL, уже написанной правильно (не путая типы аргументов!). Есть способ включить это .ddr файл в банку, которую вы создаете, так что вы можете просто позвонить sqlj.install_jar с последним параметром true поэтому он запускает команды в .ddr и ваши функции готовы к использованию. В документации есть пример Hello, world, который показывает больше того, как это делается.

Ура,
-Глава

Другие вопросы по тегам