Jackson: Skip Objects conditionally

I had a simple problem when implementing this brilliant solution in one of my REST applications: As soon I was using @JsonAnyGetter / @JsonAnySetter and the HidableSerializer together, a NPE was thrown during serialization. The Problem occured in Jackson 1.9.13 and even 2.5.0, the latest version usable with the actual Domino JVM.

  • Stack Trace
org.codehaus.jackson.map.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: ch.hasselba.Test["[anySetter]"])
null
    at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:218)
    at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:183)
    at org.codehaus.jackson.map.ser.std.SerializerBase.wrapAndThrow(SerializerBase.java:140)
    at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:158)
    at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
at ch.hasselba.HidableSerializer.serialize(HidableSerializer.java:29)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:610)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:256)
    at org.codehaus.jackson.map.ObjectMapper._configAndWriteValue(ObjectMapper.java:2575)
    at org.codehaus.jackson.map.ObjectMapper.writeValueAsString(ObjectMapper.java:2097)
    at ch.hasselba.Demo.main(Demo.java:54)
Caused by: java.lang.NullPointerException
    at org.codehaus.jackson.map.ser.std.MapSerializer.serializeFields(MapSerializer.java:243)
    at org.codehaus.jackson.map.ser.AnyGetterWriter.getAndSerialize(AnyGetterWriter.java:41)
    at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:154)
    ... 7 more

After hours of investigation, a simple solution came up on SO: The default serializer must be resolved, and then the code will work. I just had to override resolve method of my HidableSerializer:

@Override
public void resolve(SerializerProvider serializerProvider) throws JsonMappingException {
    if(defaultSerializer instanceof ResolvableSerializer) {
         ((ResolvableSerializer)defaultSerializer).resolve(serializerProvider);
    }
}

Here is a complete working example:

 

  • The Demo Code
package ch.hasselba;

import org.codehaus.jackson.Version;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.introspect.BasicBeanDescription;
import org.codehaus.jackson.map.module.SimpleModule;
import org.codehaus.jackson.map.ser.BeanSerializerModifier;

public class Demo {

    public static void main(String[] args) {

        ObjectMapper mapper = new ObjectMapper();

        // register the module
        Version version = new Version(1, 0, 0, "SNAPSHOT");
        mapper.registerModule(new SimpleModule("HidableModule", version) {
            @Override
            public void setupModule(SetupContext context) {
                super.setupModule(context);
                context.addBeanSerializerModifier(new BeanSerializerModifier() {
                    @SuppressWarnings("unchecked")
                    @Override
                    public JsonSerializer<?> modifySerializer(SerializationConfig config, BasicBeanDescription desc,
                        JsonSerializer<?> serializer) {
                        if (IHidable.class.isAssignableFrom(desc.getBeanClass())) {
                            return new HidableSerializer<Object>((JsonSerializer<Object>) serializer);
                        }
                        return serializer;
                    }
                });
            }
        });

        // the data
        String content = "{ \"foo\": \"bar\" }";

        // build the Object
        Test test = null;
        try {
            test =  mapper.readValue(content, Test.class);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // and now convert it back to a String
        String data = null;
        try {
             data = mapper.writeValueAsString(test);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println( data );

    }

}

 

  • Test Class
package ch.hasselba;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.codehaus.jackson.annotate.JsonAnyGetter;
import org.codehaus.jackson.annotate.JsonAnySetter;

public class Test implements IHidable {

    private Map<String, Object> others = new ConcurrentHashMap<String, Object>();

    @JsonAnyGetter
    public Map<String, Object> getOthers() {
        return this.others;
    }

    @JsonAnySetter
    public void addOther(final String name, final Object value) {   
        this.others.put(name, value);
    }

    @Override
    public boolean isHidden() {
        return false;
    }

}

 

  • Hideable Serializer
package ch.hasselba;

import java.io.IOException;

import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;

public class HidableSerializer<T> extends JsonSerializer<T>  implements ResolvableSerializer {

    private JsonSerializer<T> defaultSerializer;

    public HidableSerializer(JsonSerializer<T> serializer) {
        defaultSerializer = serializer;
    }

    @Override
    public void serialize(T value, JsonGenerator jgen, SerializerProvider provider)
            throws IOException, JsonProcessingException {

        if( value instanceof IHidable ){
            IHidable hidableValue = (IHidable) value;
            if( hidableValue.isHidden() )
                return;
        }
        defaultSerializer.serialize(value, jgen, provider);
    }

   @Override
   public void resolve(SerializerProvider serializerProvider) throws JsonMappingException {
       if(defaultSerializer instanceof ResolvableSerializer) {
            ((ResolvableSerializer)defaultSerializer).resolve(serializerProvider);
       }
   }
}

 

  • IHidable Interface
package ch.hasselba;

public interface IHidable {
    boolean isHidden();
}
Veröffentlicht unter Jackson, REST | Verschlagwortet mit , , , , | Hinterlasse einen Kommentar

Entwicklercamp 2017: Meine Vorträge & Hands-On

Dieses Jahr spreche ich wieder auf dem Entwicklercamp, und halte neben den Vorträgen auch noch eine Hands-On Session:

Im Laufe des Jahres 2016 kamen einige Themen hinzu, und dank FP8 wird es wohl auch einige Neuerungen geben, über die man mal reden müsste…

Hochperformante REST Schnittstellen entwickeln, die auf dem Domino Server laufen? Der Vortrag gibt Antworten auf die essentiellen Fragen des „Warum“ und des „Wieso“, und beleuchtet an praktischen Beispielen vor allem ausführlich die Frage des „Wie“.

Die praktische Umsetzung des Vortrages. Learning by doing.

Zur Anmeldung geht es hier entlang. Bis morgen (20.01.2017) gibt es auch noch den Frühbucherrabatt.

Veröffentlicht unter Allgemein, REST, XPages | Verschlagwortet mit , | Hinterlasse einen Kommentar

SNoUG 2017: Hochperformante REST Schnittstellen für Domino

Dieses Jahr spreche ich zum ersten Mal auf der SNoUG am 22. März diesen Jahres.

Wie der Name des Vortrages vermuten lässt, geht es um die Entwicklung hochperformanter REST Schnittstellen auf dem Domino Server, und der gesammelten Erfahrungen der letzten Jahre.

Es ehrt mich, auf diese kleine, aber feine Konferenz eingeladen worden zu sein, und ich freue mich auf weitere interessante Vorträge hochkarätiger Sprecher.

Zur Registrierung geht es hier entlang.

Veröffentlicht unter Allgemein, REST | Verschlagwortet mit , | Hinterlasse einen Kommentar

DomiNodeJS: Node.js on Domino

A while ago I started a new project which allows a seamless integration of Node.js into the Domino server.

The project is hosted on GitHub: https://github.com/hasselbach/dominodejs

The Node.js server is running as a DOTS task, and under the hood the J2V8 project is used for the V8 integration.

Currently, the project is a pre alpha, and it it is more for fun than for profit. There are a lot of open questions about the architecture, but it shows what cool things can be done with Domino.

Veröffentlicht unter Allgemein | 4 Kommentare

Aus aktuellem Anlass: Quo vadis, Domino?

Schon mal darüber nachgedacht, was nach 2021 kommt? Migrationen dauern lange, sind niemals vollständig, und irgend ein wichtiges Detail wird übersehen. Und in der Zwischenzeit?

Gerne biete ich meine Unterstützung an: Bei der Suche nach Alternativen für IBM Notes / Domino, bei Strategien für den Übergang, oder bei der Kopplung an neue Systeme.

Einfach mal Kontakt aufnehmen. Gern auch per Mail: contact <at> hasselba.ch

Veröffentlicht unter Allgemein | Hinterlasse einen Kommentar

Java NAPI: Enable / Disable Recycling of C Handles

Initialize Java NAPI

com.ibm.domino.napi.c.C.initLibrary( "" );

Disable Recycling

com.ibm.domino.napi.c.BackendBridge.setNoRecycle( session, session, true );

Enable Recycling

com.ibm.domino.napi.c.BackendBridge.setNoRecycle( session, session, false );

To use these methods in an agent, you have to import some Jars first.

Veröffentlicht unter Java | Verschlagwortet mit | Hinterlasse einen Kommentar

XPages & Domino JNA

Karsten Lehmann has published a very promising project named „Domino JNA„, which allows access to the underlying IBM Domino/Notes C API from Java.

If you want to use the project in a XPages, you have to add some Java permissions to the java.pol file on your server:

grant {
    permission java.util.PropertyPermission "jnidispatch.path", "write";
    permission java.util.PropertyPermission "jna.loaded", "write";
}

Additionally, you have to import the following JARS from „domino-jna\target\lib“ (after a successfull Maven build) to a directory on the server (jvm/lib/ext) or import it into an NSF:

  • commons-collections4-4.0.jar
  • jna-4.2.2.jar
  • joda-time-2.9.2.jar
Veröffentlicht unter Java, Security, Server, XPages | 1 Kommentar

Vaadin In XPages: A UIComponent for embedding Vaadin applications

I have created an UIComponent to embed Vaadin applications into XPages. It allows to run both technologies on the same site by adding it to your XPage:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view
    xmlns:xp="http://www.ibm.com/xsp/core"
    xmlns:vaadin="http://vaadin.com/xsp/control"
    createForm="false">
    

    <!-- XPages Application -->
    <xp:form>
        <xp:div id="refreshMe">
            <h1>XPage</h1>
            <xp:label
                value="#{javascript:java.lang.System.nanoTime()}"
                id="label1">
            </xp:label>
        </xp:div>
        <xp:button
            value="refresh"
            id="button1">
            <xp:eventHandler
                event="onclick"
                submit="true"
                refreshMode="partial"
                refreshId="refreshMe">
            </xp:eventHandler>
        </xp:button>
    </xp:form>
    
    <!--  VAADIN Application -->
    <vaadin:Vaadin
        id="Vaadin1"
        url = "/vaadin/"
        divId="addressbook"
        version="7.3.8"
        forceResize="true" />
        
</xp:view>

This little example shows the XPage above including the the Adressbook application:

2016-05-03 12_31_17-VaadinInXPages

The Vaadin application is reachable at „http://localhost/vaadin/“ (hosted by Domino), that’s why the property url is set to „/vaadin/„. The property divId contains the name of the application which is used as id in the DOM tree.

It is required that the VaadinComponent is not inside a xp:form element. If it detects a surrounding form, a runtime exception is thrown. That’s why you have to set createForm to false and add your own xp:form to your application, as shown in the example.

2016-05-03 12_50_11-Runtime Error

If the parameter forceResize is set to true, a CSS style sheet is added to the XPage which resizes the height of html and the body node to 100%. Otherwise the Vaadin application will not be displayed correctly.

2016-05-03 12_54_35-view-source_localhost_VaadinInXPages.nsf_index.xsp

Resource Aggregation must be disabled, otherwise it won’t work.

The sources can be found at https://github.com/hasselbach/VaadinInXPages

Veröffentlicht unter Vaadin, XPages | Verschlagwortet mit , | 2 Kommentare

EntwicklerCamp 2016: XPages erweitern und ausbauen

Die PDF Version meiner Entwickler Camp 2016 Session „XPages erweitern und ausbauen“ gibt es hier: ec2016-Votrag-XPagesErweiternUndAusbauen.pdf

Die verwendeten Sources finden sich in diesem Repository auf GitHub: ec2016-xpages-erweitern

Bei Fragen/Problemen einfach eine kurze Info an mich.

Veröffentlicht unter EC 2016, XPages | Verschlagwortet mit , | Hinterlasse einen Kommentar

EntwicklerCamp 2016: Ein Leben ohne Notes Client

Hier gibt es die PowerPoint Präsentation von meiner Entwickler Camp 2016 Session „Ein Leben ohne Notes Client“: ec2016-Votrag-LebenOhneNotesClient.pptx

Die kompletten Sources finden sich in diesem Repository auf GitHub: ec2016-ein-leben-ohne-notesclient

Bei Fragen/Problemen einfach eine kurze Info an mich.

UPDATE: Hier die PDF Version.

Veröffentlicht unter EC 2016, Java, JavaFX | Verschlagwortet mit , , | Hinterlasse einen Kommentar