joelittlejohn / jsonschema2pojo

Generate Java types from JSON or JSON Schema and annotate those types for data-binding with Jackson, Gson, etc

Home Page:http://www.jsonschema2pojo.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

how to implement a typed interface using jcodemodel ?

joerg-d-schneider-db opened this issue · comments

Hi,

I'm currently implementing a customized rule class to overcome some limitation in handling enums when generating JSONB output.

I'm stuck at the point where I need to create an inner class that implements a typed interface of JsonbAdapter <T, String>

Using JCodeModel statement of

// create an public static inner class inside the enum

			JDefinedClass c = _enum._class(JMod.PUBLIC | JMod.STATIC,
					enumDefinition.getNodeName() + EnumMapperRule.SUFFIX);

c._implements(JsonbAdapter.class)

just gives me

public static class EventTypeMapper implements JsonbAdapter {

What I actually need is

public static class EventTypeMapper implements JsonbAdapter**<EventType, String>** {

Any idea how that can be achieved with JCodeModel ?

Any help appreciated

You need to 'narrow' the class. Try using the .narrow method on the JDefinedClass and pass in the enum type and String type as arguments.

Hi,

I tried that and roughly 100+ other approaches - still no luck. Sorry for my ignorance.

My custom rule still produces "public static class EventTypeMapper implements JsonbAdapter {" instead of " public static class EventTypeMapper implements JsonbAdapter<EventType, String> {"

Here is the entire code base I'm stuck with

package com.db.dice.rules;

import java.util.List;

import javax.json.bind.adapter.JsonbAdapter;

import org.jsonschema2pojo.AnnotationStyle;
import org.jsonschema2pojo.model.EnumDefinition;
import org.jsonschema2pojo.rules.EnumRule;
import org.jsonschema2pojo.rules.RuleFactory;

import com.sun.codemodel.JClass;
import com.sun.codemodel.JClassAlreadyExistsException;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;

public class EnumMapperRule extends EnumRule {

private final RuleFactory ruleFactory;
public static final String SUFFIX = "Mapper";

protected EnumMapperRule(RuleFactory ruleFactory) {
	super(ruleFactory);
	this.ruleFactory = ruleFactory;
}

@Override
protected void applyCustomizations(EnumDefinition enumDefinition, JDefinedClass _enum) {
	if (this.ruleFactory.getGenerationConfig().getAnnotationStyle().equals(AnnotationStyle.JSONB1)
			|| this.ruleFactory.getGenerationConfig().getAnnotationStyle().equals(AnnotationStyle.JSONB1)) {
		try {
			// create an public static inner class inside the enum
			JDefinedClass c = _enum._class(JMod.PUBLIC | JMod.STATIC,
					enumDefinition.getNodeName() + EnumMapperRule.SUFFIX);
			

			if (c != null) {
				// let the class implement JsonbAdapter interface - to do : how to handle generics !!!
				JClass temp1 = _enum.owner().ref(JsonbAdapter.class);
				if(temp1.isInterface()) {
					System.out.println("JsonbAdapter is Interface");
					temp1.generify("String", String.class);
					temp1.narrow(String.class);

				} else {
					System.out.println("JsonbAdapter is not an Interface");					
				}
				
				JDefinedClass temp;
				try {
					temp = _enum.owner()._class("javax.json.bind.adapter.JsonbAdapter");
				} catch(JClassAlreadyExistsException ae) {
					temp = _enum.owner()._getClass("javax.json.bind.adapter.JsonbAdapter");						
				}
				
				if(temp != null) {
					temp.generify("String", String.class);
					temp.narrow(Object.class);
				} else {
					System.out.println("temp class is null !!!");
				}
				
				
				
				JDefinedClass adapter = c._implements(temp1);
				adapter.narrow(String.class);
				// create the adoptToJson method
				JMethod to = c.method(JMod.PUBLIC, String.class, "adaptToJson");
				to.annotate(Override.class);
				to.param(_enum, "obj");
				to.body().directStatement("return obj.value();");

				// create the adoptFromJson method
				JMethod from = c.method(JMod.PUBLIC, _enum, "adaptFromJson");
				from.annotate(Override.class);
				from.param(String.class, "obj");
				from.body().directStatement("return " + enumDefinition.getNodeName() + ".fromValue(obj);");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

}

finally made it

	    c._implements(model.ref(JsonbAdapter.class).narrow(Object.class).narrow(String.class));

produces

public class TestClass
implements JsonbAdapter<Object, String>

Thx for your help - that was the last piece missing ;-)