blob: ae9810b1880852b48537cd3f6135b3121a3c39ca [file] [log] [blame]
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
// * to you 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 org.apache.juneau.a.rttests;
import static org.apache.juneau.testutils.TestUtils.*;
import static org.junit.Assert.*;
import java.util.*;
import java.util.Map;
import javax.xml.datatype.*;
import org.apache.juneau.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.dto.html5.*;
import org.apache.juneau.json.*;
import org.apache.juneau.json.annotation.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.serializer.*;
import org.apache.juneau.transform.*;
import org.apache.juneau.utils.*;
import org.junit.*;
/**
* Tests designed to serialize and parse objects to make sure we end up
* with the same objects for all serializers and parsers.
*/
@SuppressWarnings({"unchecked","serial"})
public class RoundTripBeanMapsTest extends RoundTripTest {
static Class<?>[] ANNOTATED_CLASSES={L2.class, M2.class};
public RoundTripBeanMapsTest(String label, SerializerBuilder s, ParserBuilder p, int flags) throws Exception {
super(label, s.applyAnnotations(ANNOTATED_CLASSES), p == null ? null : p.applyAnnotations(ANNOTATED_CLASSES), flags);
}
@Override /* RoundTripTest */
public Map<Class<?>,Class<?>> getImplClasses() {
Map<Class<?>,Class<?>> m = new HashMap<>();
m.put(IBean.class, CBean.class);
return m;
}
//====================================================================================================
// IBean/ABean/Bean
//====================================================================================================
@Test
public void testImplClasses() throws Exception {
IBean bean = new CBean();
bean.setF1("bar");
bean = roundTrip(bean, IBean.class);
assertEquals("bar", bean.getF1());
bean.setF1("baz");
bean = roundTrip(bean, ABean.class);
assertEquals("baz", bean.getF1());
bean.setF1("bing");
bean = roundTrip(bean, CBean.class);
assertEquals("bing", bean.getF1());
}
//====================================================================================================
// IBean[]/ABean[]/Bean[]
//====================================================================================================
@Test
public void testImplArrayClasses() throws Exception {
IBean[] bean = new CBean[]{new CBean()};
bean[0].setF1("bar");
bean = roundTrip(bean, IBean[].class);
assertEquals("bar", bean[0].getF1());
bean[0].setF1("baz");
bean = roundTrip(bean, ABean[].class);
assertEquals("baz", bean[0].getF1());
bean[0].setF1("bing");
bean = roundTrip(bean, CBean[].class);
assertEquals("bing", bean[0].getF1());
}
//====================================================================================================
// List<IBean/ABean/Bean>
//====================================================================================================
@Test
public void testImplListClasses() throws Exception {
List<IBean> l = AList.<IBean>create(new CBean());
l.get(0).setF1("bar");
l = roundTrip(l, List.class, IBean.class);
assertEquals("bar", l.get(0).getF1());
l = roundTrip(l, LinkedList.class, IBean.class);
assertEquals("bar", l.get(0).getF1());
l.get(0).setF1("baz");
l = roundTrip(l, List.class, ABean.class);
assertEquals("baz", l.get(0).getF1());
l = roundTrip(l, LinkedList.class, ABean.class);
assertEquals("baz", l.get(0).getF1());
l.get(0).setF1("bing");
l = roundTrip(l, List.class, CBean.class);
assertEquals("bing", l.get(0).getF1());
l = roundTrip(l, LinkedList.class, CBean.class);
assertEquals("bing", l.get(0).getF1());
}
//====================================================================================================
// Map<String,IBean/ABean/Bean>
//====================================================================================================
@Test
public void testImplMap() throws Exception {
Map<String,IBean> l = new AMap<String,IBean>().append("foo", new CBean());
l.get("foo").setF1("bar");
l = roundTrip(l, Map.class, String.class, IBean.class);
assertEquals("bar", l.get("foo").getF1());
l = roundTrip(l, LinkedHashMap.class, String.class, IBean.class);
assertEquals("bar", l.get("foo").getF1());
l.get("foo").setF1("baz");
l = roundTrip(l, Map.class, String.class, ABean.class);
assertEquals("baz", l.get("foo").getF1());
l = roundTrip(l, LinkedHashMap.class, String.class, ABean.class);
assertEquals("baz", l.get("foo").getF1());
l.get("foo").setF1("bing");
l = roundTrip(l, Map.class, String.class, CBean.class);
assertEquals("bing", l.get("foo").getF1());
l = roundTrip(l, LinkedHashMap.class, String.class, CBean.class);
assertEquals("bing", l.get("foo").getF1());
}
//====================================================================================================
// Map<String,IBean/ABean/Bean>
//====================================================================================================
@Test
public void testImplMap2() throws Exception {
A b = new A(1);
b = roundTrip(b);
if (returnOriginalObject || p == null)
return;
assertEquals(0, b.f1);
assertEquals(0, b.f2);
assertEquals(1, b.f3);
assertEquals(1, b.f4);
assertEquals(0, b.getF5());
assertEquals(1, b.getF6());
}
public static interface IBean {
public String getF1();
public void setF1(String f1);
}
public static abstract class ABean implements IBean {
@Override /* IBean */
public abstract String getF1();
@Override /* IBean */
public abstract void setF1(String f1);
}
public static class CBean extends ABean {
private String f1 = "foo";
@Override /* IBean */
public String getF1() {
return f1;
}
@Override /* IBean */
public void setF1(String f1) {
this.f1 = f1;
}
}
public static class A {
@BeanIgnore
public int f1, f2;
public int f3, f4;
private int f5, f6;
@BeanIgnore
public int getF5() {
return f5;
}
public void setF5(int f5) {
this.f5 = f5;
}
public int getF6() {
return f6;
}
public void setF6(int f6) {
this.f6 = f6;
}
public A() {}
public A(int v) {
f1 = f2 = f3 = f4 = f5 = f6 = v;
}
}
//====================================================================================================
// Test @Bean(subTypes=xxx)
//====================================================================================================
@Test
public void testSubTypesUsingAnnotation() throws Exception {
JsonSerializer js = JsonSerializer.create().ssq().addBeanTypes().addRootType().build();
// Skip validation-only tests
if (isValidationOnly())
return;
Serializer s = getSerializer();
Parser p = getParser();
B1 b1 = B1.create();
Object r = s.serialize(b1);
B b = p.parse(r, B.class);
assertTrue(b instanceof B1);
assertObjectEquals("{_type:'B1',f0:'f0',f1:'f1'}", b, js);
B2 b2 = B2.create();
r = s.serialize(b2);
b = p.parse(r, B.class);
assertTrue(b instanceof B2);
assertObjectEquals("{_type:'B2',f0:'f0',f2:1}", b, js);
B3 b3 = B3.create();
r = s.serialize(b3);
b = p.parse(r, B.class);
assertTrue(b instanceof B3);
assertObjectEquals("{_type:'B3',f0:'f0',f3:'2001-01-01T12:34:56.789Z'}", b, js);
}
@Bean(
dictionary={B1.class,B2.class,B3.class}
)
public abstract static class B {
public String f0 = "f0";
}
@Bean(typeName="B1")
public static class B1 extends B {
public String f1;
public static B1 create() {
B1 b = new B1();
b.f0 = "f0";
b.f1 = "f1";
return b;
}
}
@Bean(typeName="B2")
public static class B2 extends B {
public int f2;
public static B2 create() {
B2 b = new B2();
b.f0 = "f0";
b.f2 = 1;
return b;
}
}
@Bean(typeName="B3")
public static class B3 extends B {
public XMLGregorianCalendar f3;
public static B3 create() throws Exception {
B3 b = new B3();
b.f0 = "f0";
b.f3 = DatatypeFactory.newInstance().newXMLGregorianCalendar("2001-01-01T12:34:56.789Z");
return b;
}
}
//====================================================================================================
// Test @Bean(subTypes=xxx) using BeanFilter
//====================================================================================================
@Test
public void testSubTypesUsingBeanFilter() throws Exception {
JsonSerializer js = JsonSerializer.create().ssq().build();
// Skip validation-only tests
if (isValidationOnly())
return;
Serializer s = getSerializer().builder().beanFilters(CFilter.class).build();
Parser p = getParser().builder().beanFilters(CFilter.class).build();
C1 c1 = C1.create();
Object r = s.serialize(c1);
C c = p.parse(r, C.class);
assertTrue(c instanceof C1);
assertObjectEquals("{f0:'f0',f1:'f1'}", c, js);
C2 c2 = C2.create();
r = s.serialize(c2);
c = p.parse(r, C.class);
assertTrue(c instanceof C2);
assertObjectEquals("{f0:'f0',f2:1}", c, js);
C3 c3 = C3.create();
r = s.serialize(c3);
c = p.parse(r, C.class);
assertTrue(c instanceof C3);
assertObjectEquals("{f0:'f0',f3:'2001-01-01T12:34:56.789Z'}", c, js);
}
public abstract static class C {
public String f0;
}
public static class C1 extends C {
public String f1;
public static C1 create() {
C1 c = new C1();
c.f0 = "f0";
c.f1 = "f1";
return c;
}
}
public static class C2 extends C {
public int f2;
public static C2 create() {
C2 c = new C2();
c.f0 = "f0";
c.f2 = 1;
return c;
}
}
public static class C3 extends C {
public XMLGregorianCalendar f3;
public static C3 create() throws Exception {
C3 c = new C3();
c.f0 = "f0";
c.f3 = DatatypeFactory.newInstance().newXMLGregorianCalendar("2001-01-01T12:34:56.789Z");
return c;
}
}
public static class CFilter extends BeanFilterBuilder<C> {
public CFilter() {
dictionary(CFilterDictionaryMap.class);
}
}
public static class CFilterDictionaryMap extends BeanDictionaryMap {
public CFilterDictionaryMap() {
addClass("C1", C1.class);
addClass("C2", C2.class);
addClass("C3", C3.class);
}
}
//====================================================================================================
// Test @Bean(subTypeProperty=xxx) with real bean property
//====================================================================================================
@Test
public void testSubTypePropertyWithRealPropertyUsingAnnotation() throws Exception {
// Skip validation-only tests
if (isValidationOnly())
return;
Serializer s = getSerializer();
Parser p = getParser();
BA1 ba1 = BA1.create();
Object r = s.serialize(ba1);
BA b = p.parse(r, BA.class);
assertTrue(b instanceof BA1);
assertObjectEquals("{_type:'BA1',f0a:'f0a',f0b:'f0b',f1:'f1'}", b);
}
@Bean(dictionary={BA1.class,BA2.class})
public abstract static class BA {
public String f0a, f0b;
}
@Bean(typeName="BA1")
public static class BA1 extends BA {
public String f1;
public static BA1 create() {
BA1 b = new BA1();
b.f0a = "f0a";
b.f0b = "f0b";
b.f1 = "f1";
return b;
}
}
@Bean(typeName="BA2")
public static class BA2 extends BA {
public String f2;
}
//====================================================================================================
// Test @Bean(subTypes=xxx) with real bean property using BeanFilter
//====================================================================================================
@Test
public void testSubTypePropertyWithRealPropertyUsingBeanFilter() throws Exception {
// Skip validation-only tests
if (isValidationOnly())
return;
Serializer s = getSerializer().builder().beanFilters(CAFilter.class).build();
Parser p = getParser().builder().beanFilters(CAFilter.class).build();
CA1 c1 = CA1.create();
Object r = s.serialize(c1);
CA c = p.parse(r, CA.class);
assertTrue(c instanceof CA1);
assertObjectEquals("{f0a:'f0a',f0b:'f0b',f1:'f1'}", c);
}
public abstract static class CA {
public String f0a, f0b;
}
public static class CA1 extends CA {
public String f1;
public static CA1 create() {
CA1 c = new CA1();
c.f0a = "f0a";
c.f0b = "f0b";
c.f1 = "f1";
return c;
}
}
public static class CA2 extends CA {
public String f2;
}
public static class CAFilter extends BeanFilterBuilder<CA> {
public CAFilter() {
dictionary(CAFilterDictionaryMap.class);
}
}
public static class CAFilterDictionaryMap extends BeanDictionaryMap {
public CAFilterDictionaryMap() {
addClass("CA1", CA1.class);
addClass("CA2", CA2.class);
}
}
//====================================================================================================
// Test @Bean(bpi=xxx)
//====================================================================================================
@Test
public void testPropertiesUsingAnnotation() throws Exception {
// Skip validation-only tests
if (isValidationOnly())
return;
Serializer s = getSerializer();
Parser p = getParser();
D1 d = new D1().init();
Object r = s.serialize(d);
d = p.parse(r, D1.class);
assertNull(d.f1);
assertObjectEquals("{f3:'f3',f2:'f2'}", d);
}
@Bean(bpi="f3,f2")
public static class D1 {
public String f1, f2, f3;
public D1 init() {
f1 = "f1";
f2 = "f2";
f3 = "f3";
return this;
}
}
//====================================================================================================
// Test @Bean(bpi=xxx) using BeanFilter
//====================================================================================================
@Test
public void testPropertiesUsingBeanFilter() throws Exception {
JsonSerializer js = JsonSerializer.create().ssq().beanFilters(D2Filter.class).build();
// Skip validation-only tests
if (isValidationOnly())
return;
Serializer s = getSerializer().builder().beanFilters(D2Filter.class).build();
Parser p = getParser().builder().beanFilters(D2Filter.class).build();
D2 d = new D2().init();
Object r = s.serialize(d);
d = p.parse(r, D2.class);
assertNull(d.f1);
assertObjectEquals("{f3:'f3',f2:'f2'}", d, js);
}
public static class D2 {
public String f1, f2, f3;
public D2 init() {
f1 = "f1";
f2 = "f2";
f3 = "f3";
return this;
}
}
public static class D2Filter extends BeanFilterBuilder<D2> {
public D2Filter() {
bpi("f3,f2");
}
}
//====================================================================================================
// Test @Bean(bpx=xxx)
//====================================================================================================
@Test
public void testExcludePropertiesUsingAnnotation() throws Exception {
// Skip validation-only tests
if (isValidationOnly())
return;
Serializer s = getSerializer();
Parser p = getParser();
E1 e = new E1().init();
Object r = s.serialize(e);
e = p.parse(r, E1.class);
assertObjectEquals("{f1:'f1',f3:'f3'}", e);
}
@Bean(bpx="f2")
public static class E1 {
public String f1, f2, f3;
public E1 init() {
f1 = "f1";
f2 = "f2";
f3 = "f3";
return this;
}
}
//====================================================================================================
// Test @Bean(bpx=xxx) using BeanFilter
//====================================================================================================
@Test
public void testExcludePropertiesUsingBeanFilter() throws Exception {
// Skip validation-only tests
if (isValidationOnly())
return;
Serializer s = getSerializer().builder().beanFilters(E2Filter.class).build();
Parser p = getParser().builder().beanFilters(E2Filter.class).build();
E2 e = new E2().init();
Object r = s.serialize(e);
e = p.parse(r, E2.class);
assertObjectEquals("{f1:'f1',f3:'f3'}", e);
}
public static class E2 {
public String f1, f2, f3;
public E2 init() {
f1 = "f1";
f2 = "f2";
f3 = "f3";
return this;
}
}
public static class E2Filter extends BeanFilterBuilder<E2> {
public E2Filter() {
bpx("f2");
}
}
//====================================================================================================
// Test @Bean(interfaceClass=xxx)
//====================================================================================================
@Test
public void testInterfaceClassUsingAnnotation() throws Exception {
// Skip validation-only tests
if (isValidationOnly())
return;
Serializer s = getSerializer();
Parser p = getParser();
FA2 t = new FA2().init();
Object r = s.serialize(t);
t = p.parse(r, FA2.class);
assertObjectEquals("{f1:'f1'}", t);
}
@Bean(interfaceClass=FA1.class)
public static class FA1 {
public String f1;
}
public static class FA2 extends FA1 {
public String f2;
public FA2 init() {
f1 = "f1";
f2 = "f2";
return this;
}
}
//====================================================================================================
// Test @Bean(interfaceClass=xxx) using BeanFilter
//====================================================================================================
@Test
public void testInterfaceClassUsingBeanFilter() throws Exception {
SerializerBuilder s = getSerializer().builder();
ParserBuilder p = getParser() == null ? null : getParser().builder();
FB2 t;
Object r;
// Skip validation-only tests
if (isValidationOnly())
return;
// --- BeanFilter defined on parent class ---
s.beanFilters(FB1Filter.class);
p.beanFilters(FB1Filter.class);
t = new FB2().init();
r = s.build().serialize(t);
t = p.build().parse(r, FB2.class);
assertObjectEquals("{f1:'f1'}", t);
// --- BeanFilter defined on child class class ---
s.beanFilters(FB2Filter.class);
p.beanFilters(FB2Filter.class);
t = new FB2().init();
r = s.build().serialize(t);
t = p.build().parse(r, FB2.class);
assertObjectEquals("{f1:'f1'}", t);
// --- BeanFilter defined as plain class ---
s.beanFilters(FB1.class);
p.beanFilters(FB1.class);
t = new FB2().init();
r = s.build().serialize(t);
t = p.build().parse(r, FB2.class);
assertObjectEquals("{f1:'f1'}", t);
}
public static class FB1 {
public String f1;
}
public static class FB2 extends FB1 {
public String f2;
public FB2 init() {
f1 = "f1";
f2 = "f2";
return this;
}
}
public static class FB1Filter extends InterfaceBeanFilterBuilder<FB1> {}
public static class FB2Filter extends InterfaceBeanFilterBuilder<FB1> {}
//====================================================================================================
// testMemberClass
//====================================================================================================
@Test
public void testMemberClass() throws Exception {
G t = G.create();
t = roundTrip(t, G.class);
}
public static class G {
public int a1;
public G1 g1;
public static G create() {
G g = new G();
g.a1 = 1;
g.g1.a2 = 2;
g.g1.g2.a3 = 3;
return g;
}
public G() {
g1 = new G1();
}
public class G1 {
public int a2;
public G2 g2;
public G1() {
g2 = new G2();
}
public class G2 {
public int a3;
}
}
}
//====================================================================================================
// testMemberClassWithMapClass
//====================================================================================================
@Test
public void testMemberClassWithMapClass() throws Exception {
H t = H.create();
t = roundTrip(t, H.class);
}
public static class H extends LinkedHashMap<String,H.H1> {
static H create() {
H h = new H();
h.add("foo", 1, 2);
return h;
}
H add(String key, int a2, int a3) {
H1 h1 = new H1();
h1.a2 = a2;
h1.h2.a3 = a3;
put(key, h1);
return this;
}
public class H1 {
public int a2;
public H2 h2;
public H1() {
h2 = new H2();
}
public class H2 {
public int a3;
}
}
}
//====================================================================================================
// testMemberClassWithListClass
//====================================================================================================
@Test
public void testMemberClassWithListClass() throws Exception {
I t = I.create();
t = roundTrip(t, I.class);
}
public static class I extends LinkedList<I.I1> {
static I create() {
I i = new I();
i.add(1, 2);
return i;
}
I add(int a2, int a3) {
I1 i1 = new I1();
i1.a2 = a2;
i1.i2.a3 = a3;
super.add(i1);
return this;
}
public class I1 {
public int a2;
public I2 i2;
public I1() {
i2 = new I2();
}
public class I2 {
public int a3;
}
}
}
//====================================================================================================
// testMemberClassWithStringConstructor
//====================================================================================================
@Test
public void testMemberClassWithStringConstructor() throws Exception {
J t = J.create();
t = roundTrip(t, J.class);
}
public static class J {
public J2 j2;
static J create() {
J j = new J();
j.init();
return j;
}
private void init() {
j2 = new J2("2");
}
public class J2 {
int a2;
public J2(String arg) {
this.a2 = Integer.parseInt(arg);
}
@Override /* Object */
public String toString() {
return String.valueOf(a2);
}
}
}
//====================================================================================================
// testBeanPropertyPrecedence
//====================================================================================================
@Test
public void testBeanPropertyPrecedence() throws Exception {
K t = K.create();
t = roundTrip(t, K.class);
}
public static enum KEnum { FOO, BAR, BAZ }
public static class K {
private KEnum a, b, c;
static K create() {
K t = new K();
t.a = KEnum.FOO;
t.b = KEnum.BAR;
t.c = KEnum.BAZ;
return t;
}
@BeanIgnore
public KEnum getA() {
return KEnum.FOO;
}
@Beanp(name="a")
public String getA2() {
return a.toString();
}
// This method should not be interpreted as the setter for this
// property because it doesn't match the getter return type above.
public void setA(KEnum a) {
throw new RuntimeException("Should not be called!");
}
public void setA(String a) {
this.a = KEnum.valueOf(a);
}
public KEnum getB() {
return b;
}
public void setB(String b) {
throw new RuntimeException("Should not be called!");
}
public void setB(Object b) {
throw new RuntimeException("Should not be called!");
}
public void setB(KEnum b) {
this.b = b;
}
public KEnum getC() {
return c;
}
public void setC(KEnum c) {
this.c = c;
}
public void setC(String c) {
throw new RuntimeException("Should not be called!");
}
public void setC(Object c) {
throw new RuntimeException("Should not be called!");
}
}
//====================================================================================================
// testWrapperAttrAnnotationOnBean
//====================================================================================================
@Test
public void testWrapperAttrAnnotationOnBean() throws Exception {
L t = L.create();
t = roundTrip(t, L.class);
Map<String,L> m = new LinkedHashMap<>();
m.put("bar", L.create());
roundTrip(m, LinkedHashMap.class, String.class, L.class);
}
@Json(wrapperAttr="foo")
public static class L {
public int f1;
static L create() {
L l = new L();
l.f1 = 1;
return l;
}
}
@Test
public void testWrapperAttrAnnotationOnBean_usingConfig() throws Exception {
L2 t = L2.create();
t = roundTrip(t, L2.class);
Map<String,L2> m = new LinkedHashMap<>();
m.put("bar", L2.create());
roundTrip(m, LinkedHashMap.class, String.class, L2.class);
}
@JsonConfig(annotateJson=@Json(on="L2",wrapperAttr="foo"))
public static class L2 {
public int f1;
static L2 create() {
L2 l = new L2();
l.f1 = 1;
return l;
}
}
//====================================================================================================
// testWrapperAttrAnnotationOnNonBean
//====================================================================================================
@Test
public void testWrapperAttrAnnotationOnNonBean() throws Exception {
M t = M.create();
t = roundTrip(t, M.class);
Map<String,M> m = new LinkedHashMap<>();
m.put("bar", M.create());
roundTrip(m, LinkedHashMap.class, String.class, M.class);
}
@Json(wrapperAttr="foo")
public static class M {
int f1;
static M create() {
M m = new M();
m.f1 = 1;
return m;
}
@Override /* Object */
public String toString() {
return String.valueOf(f1);
}
public static M valueOf(String s) {
M m = new M();
m.f1 = Integer.parseInt(s);
return m;
}
}
@Test
public void testWrapperAttrAnnotationOnNonBean_usingConfig() throws Exception {
M2 t = M2.create();
t = roundTrip(t, M2.class);
Map<String,M2> m = new LinkedHashMap<>();
m.put("bar", M2.create());
roundTrip(m, LinkedHashMap.class, String.class, M2.class);
}
@JsonConfig(annotateJson=@Json(on="M2",wrapperAttr="foo"))
public static class M2 {
int f1;
static M2 create() {
M2 m = new M2();
m.f1 = 1;
return m;
}
@Override /* Object */
public String toString() {
return String.valueOf(f1);
}
public static M2 valueOf(String s) {
M2 m = new M2();
m.f1 = Integer.parseInt(s);
return m;
}
}
//====================================================================================================
// testBeanPropertyWithBeanWithAttrsField
//====================================================================================================
@Test
public void testBeanPropertyWithBeanWithAttrsField() throws Exception {
N t = N.create();
t = roundTrip(t, N.class);
t.f1.type("foo");
t = roundTrip(t, N.class);
t.f1.attr("foo", "bar").attrUri("href", "http://foo");
t = roundTrip(t, N.class);
Head h = new Head().child(new Style());
h = roundTrip(h, Head.class);
}
public static class N {
public Style f1;
static N create() {
N n = new N();
n.f1 = new Style();
return n;
}
}
}