Архивы: google app engine

NullPointerException при парсинге ошибки в CancelPreapprovalResponse в PayPal X GAE Toolkit

Вообще говоря и отмена preapproval платежа не работает, но это другой вопрос, а вот при попытке распарсить сообщение об ошибке библиотека выкидывает NullPointerException. Происходит это потому, что для массива, куда складываются сообщения, не выделена память.

На трекер запостил, но пока ещё не добавили в репозиторий — ловите патч.

1
2
3
4
5
6
7
8
9
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
48
49
50
51
 Index: src/com/paypal/adaptive/api/responses/CancelPreapprovalResponse.java
===================================================================
--- src/com/paypal/adaptive/api/responses/CancelPreapprovalResponse.java    (revision 13)
+++ src/com/paypal/adaptive/api/responses/CancelPreapprovalResponse.java    (working copy)
@@ -17,6 +17,13 @@
    protected ResponseEnvelope responseEnvelope;
    protected ArrayList<payerror> payErrorList;
 
+   /**
+    * @return the payErrorList
+    */
+   public ArrayList<payerror> getPayErrorList() {
+       return payErrorList;
+   }
+  
     /**
      * Gets the value of the responseEnvelope property.
      *
@@ -29,6 +36,13 @@
         return responseEnvelope;
     }
 
+   /**
+    * @param payErrorList the payErrorList to set
+    */
+   public void setPayErrorList(ArrayList<payerror> payErrorList) {
+       this.payErrorList = payErrorList;
+   }
+  
     /**
      * Sets the value of the responseEnvelope property.
      *
@@ -39,7 +53,7 @@
      */
     public void setResponseEnvelope(ResponseEnvelope value) {
         this.responseEnvelope = value;
-    }
+    } 
 
     public CancelPreapprovalResponse(String responseString){
       
@@ -52,7 +66,8 @@
        }
 
        responseEnvelope = new ResponseEnvelope(preapprovalDetailsResponseParams);
-              
+      
+       payErrorList = new ArrayList<payerror>();
        // we will parse 10 errors for now
        for(int i = 0; i &lt; 10; i++){
            if(preapprovalDetailsResponseParams.containsKey("error(" + i +").errorId")){

Google App Engine и индексы

В случае, если при запросе у вас используется несколько условий, то GAE требует наличия индексов, другими словами, вот такой вот запрос отработает без индексов:

1
SELECT * FROM HyperLink WHERE param1 == 1

А вот такой потребует создания индекса:

1
SELECT * FROM HyperLink WHERE param1 == 1 && param2 == 2

Если вы программируете на Java, то, при локальной разработке, как только сервер выполнит запрос и обнаружит в нём два условия, то сгенерирует xml файл datastore-indexes-auto.xml примерно такого содержания:

1
2
3
4
5
6
7
8
9
10
<!-- Indices written at Sat, 8 Jan 2011 11:58:41 UTC -->

<datastore-indexes>

    <!-- Used 2 times in query history -->
    <datastore-index source="auto" ancestor="true" kind="HyperLink">
        <property direction="asc" name="param2"></property>
    </datastore-index>

</datastore-indexes>

Локально всё будет работать, но после deployment — com.google.appengine.api.datastore.DatastoreNeedIndexException. WTF!?

Оказывается, надо дописать в этот файл параметр autoGenerate=»true». Вот так:

1
2
3
4
5
6
7
8
9
10
<!-- Indices written at Sat, 8 Jan 2011 11:58:41 UTC -->

<datastore-indexes autogenerate="true">

    <!-- Used 2 times in query history -->
    <datastore-index source="auto" ancestor="true" kind="HyperLink">
        <property direction="asc" name="param2"></property>
    </datastore-index>

</datastore-indexes>

Попробуйте обратить на это внимание при первом прочтении документации. Даже при втором.

GAE и Java

Google App Engine и Java это вообще ад и погибель. Тогда как с питоном работать просто и удобно, здесь как по граблям идёшь. Постоянно какие-то глюки, которые или не документированы, или важная информация засунута настолько глубоко, что ищется только после получаса настойчивого гугления.

Поэтому, если у вас будет выбор на чём начинать проект для GAE. Не берите Java.

Google App Engine и хранение объектов в сессии

В GAE бывает довольно удобно хранить объекты в текущей сессии пользователя. Например, некоторый класс, который отвечает за параметры текущего пользователя. Пусть он называется Account.

1
2
3
4
5
6
7
8
9
10
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Account {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

    @Persistent private String email;
   
    // Здесь ещё всякие поля и методы.
}

Всё работает замечательно, до тех пор пока вы не сделаете deploy. Тут всё чудесным образом начнёт отваливаться с java.lang.RuntimeException: java.io.NotSerializableException

Хотя, казалось бы, а чего оно работает тогда локально. Ну да ладно. Решение простое. Надо сделать классу implements Serializable, т.е. получится что-то такое.

1
2
3
4
5
6
7
8
9
10
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Account implements Serializable {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

    @Persistent private String email;
   
    // Здесь ещё всякие поля и методы.
}

Такие дела.