[forge-issues] [JBoss JIRA] (FORGE-481) JavaParser.parse gets confused on inner classes

Richard Kennard (JIRA) jira-events at lists.jboss.org
Thu Feb 23 21:45:36 EST 2012


Richard Kennard created FORGE-481:
-------------------------------------

             Summary: JavaParser.parse gets confused on inner classes
                 Key: FORGE-481
                 URL: https://issues.jboss.org/browse/FORGE-481
             Project: Forge
          Issue Type: Bug
            Reporter: Richard Kennard


While developing the AeroGear scaffold, I discovered that if I do...

{noformat}
         // Generate ObjectMapperProviderTemplate.jv
         JavaClass objectMapperProvider = JavaParser.parse(JavaClass.class,
                  this.objectMapperProviderTemplate.render(context));
         objectMapperProvider.setPackage(serviceBean.getPackage());
         result.add(ScaffoldUtil.createOrOverwrite(this.prompt, java.getJavaResource(objectMapperProvider),
                  objectMapperProvider.toString(),
                  true));
{noformat}

...with a ObjectMapperProviderTemplate.jv of...


{noformat}
import java.io.IOException;
import java.lang.reflect.Method;

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.deser.BeanDeserializer;
import org.codehaus.jackson.map.deser.CustomDeserializerFactory;
import org.codehaus.jackson.map.deser.StdDeserializerProvider;
import org.codehaus.jackson.map.introspect.BasicBeanDescription;
import org.codehaus.jackson.map.ser.BeanSerializer;
import org.codehaus.jackson.map.ser.CustomSerializerFactory;
import org.codehaus.jackson.type.JavaType;

/**
 * Custom JSON ObjectMapper that knows how to lookup JPA entities based on ids.
 */

@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
	private final ObjectMapper mapper;

	@PersistenceContext
	private EntityManager entityManager;

	public ObjectMapperProvider() {

		this.mapper = new ObjectMapper();

		// Serialize

		CustomSerializerFactory serializer = new CustomSerializerFactory() {

			@Override
			protected JsonSerializer<Object> constructBeanSerializer(
					SerializationConfig config, BasicBeanDescription beanDesc) {

				BeanSerializer beanSerializer = (BeanSerializer) super
						.constructBeanSerializer(config, beanDesc);
				return new JpaSerializer(beanSerializer);
			}
		};
		this.mapper.setSerializerFactory(serializer);

		// Deserialize

		this.mapper.setDeserializerProvider(new StdDeserializerProvider(
				new CustomDeserializerFactory() {

					protected BeanDeserializer constructBeanDeserializerInstance(
							DeserializationConfig config, JavaType type,
							BasicBeanDescription beanDesc) {

						return new JpaDeserializer(type);
					}
				}));
	}

	@Override
	public ObjectMapper getContext(Class<?> type) {
		return this.mapper;
	}

	//
	// Inner classes
	//

	private class JpaSerializer extends JsonSerializer<Object> {

		private BeanSerializer delegate;

		private Method serializeFields;

		public JpaSerializer(BeanSerializer delegate) {
			this.delegate = delegate;
			try {
				this.serializeFields = BeanSerializer.class.getDeclaredMethod(
						"serializeFields", Object.class, JsonGenerator.class,
						SerializerProvider.class);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
			this.serializeFields.setAccessible(true);
		}

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

			jgen.writeStartObject();

			// Special support for toString...

			provider.getKeySerializer().serialize("toString", jgen, provider);
			provider.findTypedValueSerializer(String.class, true).serialize(
					value.toString(), jgen, provider);

			// ...then delegate

			try {
				this.serializeFields.invoke(this.delegate, value, jgen,
						provider);
			} catch (Exception e) {
				throw new IOException(e);
			}
			jgen.writeEndObject();
		}
	}

	private class JpaDeserializer extends BeanDeserializer {

		public JpaDeserializer(JavaType type) {
			super(type);
		}

		public Object deserializeFromString(JsonParser jp,
				DeserializationContext ctxt) throws IOException,
				JsonProcessingException {

			// Special support for JPA entities...

			if (this.getBeanClass().isAnnotationPresent(Entity.class)) {
				return ObjectMapperProvider.this.entityManager.find(
						this.getBeanClass(), Long.valueOf(jp.getText()));
			}

			// ...or delegate

			return super.deserializeFromString(jp, ctxt);
		}
	}
}
{noformat}

...then it ends up creating a Java file called JpaDeserializer.java, not ObjectMapperProvider.java. If I do...

{noformat}
         // Generate ObjectMapperProviderTemplate.jv
         JavaClass objectMapperProvider = JavaParser.parse(JavaClass.class,
                  this.objectMapperProviderTemplate.render(context));
         objectMapperProvider.setPackage(serviceBean.getPackage());
         result.add(ScaffoldUtil.createOrOverwrite(this.prompt, java.getJavaResource(serviceBean.getPackage() + ".ObjectMapperProvider.java"),
                  objectMapperProvider.toString(),
                  true));
{noformat}

...then it's fine.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: https://issues.jboss.org/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira

        


More information about the forge-issues mailing list