/* * Copyright 2017 jefrajames. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package lab.jefrajames.jsonb; import java.text.ParseException; import java.time.LocalDate; import java.time.Month; import java.util.Objects; import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; import javax.json.bind.Jsonb; import javax.json.bind.JsonbBuilder; import javax.json.bind.annotation.JsonbProperty; import org.junit.AfterClass; import static org.junit.Assert.assertEquals; import org.junit.BeforeClass; import org.junit.Test; /** * This test illustrates an unexpected error while marshalling an * Optional attribute on an inner class * * According to the spec (see chapters 3.7.2 and 3.7.3) binding of nested classes * should work. * * @author jefrajames */ public class NestedClassTest { private static final Logger LOG = Logger.getLogger(NestedClassTest.class.getName()); private static Jsonb jsonb; @BeforeClass public static void beforeClass() { jsonb = JsonbBuilder.create(); } @AfterClass public static void afterClass() throws Exception { if (jsonb != null) { jsonb.close(); } } @Test public void testWithLocalDate() throws ParseException { // Person initialData = new Person("John", Optional.of(new SimpleDateFormat("dd.MM.yyy").parse("05.07.2016"))); Character initialData = new Character("John", Optional.of(LocalDate.of(1971, Month.MAY, 28))); LOG.log(Level.INFO, "initialData={0}", initialData); // JsonbException happens here: Error getting value on Person ... String jsonForm = jsonb.toJson(initialData, Character.class); LOG.log(Level.INFO, "jsonForm={0}", jsonForm); Character fromJson = jsonb.fromJson(jsonForm, Character.class); LOG.log(Level.INFO, "fromJson={0}", fromJson); assertEquals(initialData, fromJson); } @Test public void testEmptyOptional() throws ParseException { Character initialData = new Character("Jim", Optional.empty()); LOG.log(Level.INFO, "initialData={0}", initialData); // JsonbException happens here: Error getting value on Person ... String jsonForm = jsonb.toJson(initialData, Character.class); LOG.log(Level.INFO, "jsonForm={0}", jsonForm); Character fromJson = jsonb.fromJson(jsonForm, Character.class); LOG.log(Level.INFO, "fromJson={0}", fromJson); assertEquals(initialData, fromJson); } /** * Nested classe: when externalized it works! * */ class Character { private String name; @JsonbProperty(nillable = true) private Optional weddingDate; public Character() { } public Character(String name, Optional weddingDate) { this.name = name; this.weddingDate = weddingDate; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Optional getWeddingDate() { return weddingDate; } public void setWeddingDate(Optional weddingDate) { this.weddingDate = weddingDate; } @Override public int hashCode() { int hash = 7; hash = 37 * hash + Objects.hashCode(this.name); hash = 37 * hash + Objects.hashCode(this.weddingDate); return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Character other = (Character) obj; if (!Objects.equals(this.name, other.name)) { return false; } if (!Objects.equals(this.weddingDate, other.weddingDate)) { return false; } return true; } @Override public String toString() { return "Person{" + "name=" + name + ", weddingDate=" + weddingDate + '}'; } } }