Skip to content

Commit

Permalink
Implement #246, works awesome in tests, not so much in an OSGi contai…
Browse files Browse the repository at this point in the history
…ner for some reason
  • Loading branch information
gashcrumb committed Apr 11, 2013
1 parent db86d6f commit 6d8a50f
Show file tree
Hide file tree
Showing 17 changed files with 317 additions and 16 deletions.
6 changes: 5 additions & 1 deletion hawtio-json-schema-mbean/pom.xml
Expand Up @@ -20,10 +20,12 @@
<jackson-module-jaxb-annotations-version>2.1.3</jackson-module-jaxb-annotations-version>
<reflections-version>0.9.9-RC1</reflections-version>
<fuse.osgi.export>
io.hawt.jsonschema
io.hawt.jsonschema,
io.hawt.jsonschema.api
</fuse.osgi.export>
<fuse.osgi.import>
io.hawt.jsonschema,
io.hawt.jsonschema.api,
*;resolution:=optional
</fuse.osgi.import>
</properties>
Expand Down Expand Up @@ -85,12 +87,14 @@
<version>${jackson-version}</version>
</dependency>

<!--
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>${osgi-version}</version>
<scope>provided</scope>
</dependency>
-->

<dependency>
<groupId>junit</groupId>
Expand Down
Expand Up @@ -3,13 +3,17 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
import io.hawt.jsonschema.api.MixInAnnotation;
import io.hawt.jsonschema.internal.BeanValidationAnnotationModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
import java.util.HashMap;
import java.util.Map;

/**
* @author Stan Lewis
Expand All @@ -21,6 +25,7 @@ public class SchemaLookup implements SchemaLookupMXBean {

private MBeanServer mBeanServer;
private ObjectName objectName;
private Map<Class<?>, Class<?>> mixins = new HashMap<Class<?>, Class<?>>();

private ObjectMapper mapper;

Expand Down Expand Up @@ -81,7 +86,7 @@ public void destroy() {
}
}

private Class getClass(String name) {
protected Class getClass(String name) {
// TODO - well, this relies on DynamicImport-Package to work, but seems simpler than mucking about with org.osgi.framework.wiring
try {
return Class.forName(name);
Expand All @@ -91,6 +96,25 @@ private Class getClass(String name) {
}
}

public void registerMixIn(MixInAnnotation mixin) {
// Just to be on the safe side, force loading the classes directly to avoid
// any odd proxy classes which will screw up our mixin' in
Class target = getClass(mixin.getTarget().getCanonicalName());
Class mixinSource = getClass(mixin.getMixinSource().getCanonicalName());
LOG.info("Adding mixin for target class " + target.getCanonicalName() + " using annotation source " + mixinSource.getCanonicalName());
mixins.put(target, mixinSource);
getMapper().setMixInAnnotations(mixins);
LOG.debug("Current mixin count: " + getMapper().mixInCount());
}

public void unregisterMixIn(MixInAnnotation mixin) {
if (mixin != null) {
LOG.info("Removing mixin for target class " + mixin.getTarget().getCanonicalName() + " using annotation source " + mixin.getMixinSource().getCanonicalName());
mixins.remove(mixin.getTarget());
getMapper().setMixInAnnotations(mixins);
LOG.debug("Current mixin count: " + getMapper().mixInCount());
}
}

@Override
public String getSchemaForClass(String name) {
Expand All @@ -99,6 +123,7 @@ public String getSchemaForClass(String name) {
}

public String getSchemaForClass(Class clazz) {
LOG.info("Looking up schema for " + clazz.getCanonicalName());
String name = clazz.getName();
try {
ObjectWriter writer = mapper.writer().withDefaultPrettyPrinter();
Expand Down
@@ -0,0 +1,19 @@
package io.hawt.jsonschema.api;

/**
* @author Stan Lewis
*/
public interface MixInAnnotation {

/**
* Return the class or interface whose annotations will be added to the target's annotations, overriding as needed
*/
Class getMixinSource();

/**
* Return the target class or interface whose annotations should be overridden
*/

Class getTarget();

}
@@ -1,4 +1,4 @@
package io.hawt.jsonschema;
package io.hawt.jsonschema.internal;

import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
Expand Down
@@ -1,4 +1,4 @@
package io.hawt.jsonschema;
package io.hawt.jsonschema.internal;

import com.fasterxml.jackson.databind.module.SimpleModule;

Expand All @@ -15,7 +15,7 @@ public BeanValidationAnnotationModule() {
public void setupModule(SetupContext context) {
BeanValidationAnnotationIntrospector introspector = new BeanValidationAnnotationIntrospector(context.getTypeFactory());

context.appendAnnotationIntrospector(introspector);
context.insertAnnotationIntrospector(introspector);
}

}
Expand Up @@ -2,6 +2,11 @@
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.2.0">


<reference-list id="mixin-annotations" availability="optional" interface="io.hawt.jsonschema.api.MixInAnnotation">
<reference-listener ref="schemaLookup" bind-method="registerMixIn" unbind-method="unregisterMixIn"/>
</reference-list>

<bean id="schemaLookup" class="io.hawt.jsonschema.SchemaLookup" init-method="init" destroy-method="destroy"/>

</blueprint>
Expand Down
@@ -1,5 +1,9 @@
package io.hawt.jsonschema;
package io.hawt.jsonschema.test;

import io.hawt.jsonschema.SchemaLookup;
import io.hawt.jsonschema.api.MixInAnnotation;
import io.hawt.jsonschema.test.objects.ObjectWithJsonAnnotations;
import io.hawt.jsonschema.test.objects.ObjectWithMixinOverride;
import org.junit.Assert;
import org.junit.Test;

Expand All @@ -18,7 +22,7 @@ public void testLookupSchema() throws Exception {
public void testLookupMoreInterestingSchema() throws Exception {
SchemaLookup lookup = createSchemaLookup();
String result = lookup.getSchemaForClass("org.fusesource.fabric.api.CreateSshContainerOptions");
System.out.println("Got: \n\n" + result + "\n\n");
System.out.println("testLookupMoreInterestingSchema - Got: \n\n" + result + "\n\n");
}

@Test
Expand All @@ -42,22 +46,45 @@ protected SchemaLookup createSchemaLookup() {
@Test
public void testObjectWithJaxbAnnotations() throws Exception {
SchemaLookup lookup = createSchemaLookup();
String result = lookup.getSchemaForClass("io.hawt.jsonschema.ObjectWithJaxbAnnotations");
System.out.println("Got: \n\n" + result + "\n\n");
String result = lookup.getSchemaForClass("io.hawt.jsonschema.test.objects.ObjectWithJaxbAnnotations");
System.out.println("testObjectWithJaxbAnnotations - Got: \n\n" + result + "\n\n");
}

@Test
public void testObjectWithValidationAnnotations() throws Exception {
SchemaLookup lookup = createSchemaLookup();
String result = lookup.getSchemaForClass("io.hawt.jsonschema.ObjectWithValidationAnnotations");
System.out.println("Got: \n\n" + result + "\n\n");
String result = lookup.getSchemaForClass("io.hawt.jsonschema.test.objects.ObjectWithValidationAnnotations");
System.out.println("testObjectWithValidationAnnotations - Got: \n\n" + result + "\n\n");
}

@Test
public void testObjectWithJsonAnnotations() throws Exception {
SchemaLookup lookup = createSchemaLookup();
String result = lookup.getSchemaForClass("io.hawt.jsonschema.ObjectWithJsonAnnotations");
System.out.println("Got: \n\n" + result + "\n\n");
String result = lookup.getSchemaForClass("io.hawt.jsonschema.test.objects.ObjectWithJsonAnnotations");
System.out.println("testObjectWithJsonAnnotations - Got: \n\n" + result + "\n\n");
}

@Test
public void testOverrideObjectViaMixin() throws Exception {
SchemaLookup lookup = createSchemaLookup();
lookup.registerMixIn(new MixInAnnotation() {

@Override
public Class getMixinSource() {
return ObjectWithMixinOverride.class;
}

@Override
public Class getTarget() {
return ObjectWithJsonAnnotations.class;
}
});

String result = lookup.getSchemaForClass("io.hawt.jsonschema.test.objects.ObjectWithJsonAnnotations");
System.out.println("testOverrideObjectViaMixin - Got: \n\n" + result + "\n\n");

Assert.assertTrue(!result.contains("foobar"));

}

}
@@ -1,4 +1,4 @@
package io.hawt.jsonschema;
package io.hawt.jsonschema.test.objects;

/**
* @author Stan Lewis
Expand Down
@@ -1,4 +1,4 @@
package io.hawt.jsonschema;
package io.hawt.jsonschema.test.objects;

import com.fasterxml.jackson.annotation.JsonProperty;

Expand Down
@@ -0,0 +1,13 @@
package io.hawt.jsonschema.test.objects;

import com.fasterxml.jackson.annotation.JsonProperty;

/**
* @author Stan Lewis
*/
public class ObjectWithMixinOverride {

@JsonProperty(value="cheese")
public String string1;

}
@@ -1,4 +1,4 @@
package io.hawt.jsonschema;
package io.hawt.jsonschema.test.objects;


import javax.validation.constraints.NotNull;
Expand Down
40 changes: 40 additions & 0 deletions hawtio-json-schema-mixins/pom.xml
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>project</artifactId>
<groupId>io.hawt</groupId>
<version>1.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>hawtio-json-schema-mixins</artifactId>

<dependencies>

<dependency>
<groupId>io.hawt</groupId>
<artifactId>hawtio-json-schema-mbean</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.fusesource.fabric</groupId>
<artifactId>fabric-core</artifactId>
<version>${fabric-version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit-version}</version>
<scope>test</scope>
</dependency>

</dependencies>



</project>
@@ -0,0 +1,53 @@
package io.hawt.jsonschema.mixins;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.hawt.jsonschema.api.MixInAnnotation;
import org.fusesource.fabric.api.CreateContainerBasicOptions;
import org.fusesource.fabric.api.CreateContainerMetadata;
import org.fusesource.fabric.api.CreationStateListener;

import java.util.Map;

/**
* @author Stan Lewis
*/
public class CreateContainerBasicMixinOverrides implements MixInAnnotation {

@Override
public Class getMixinSource() {
return CreateContainerMixin.class;
}

@Override
public Class getTarget() {
return CreateContainerBasicOptions.class;
}
}


abstract class CreateContainerMixin extends CreateContainerBasicOptions {

@JsonIgnore
protected String zookeeperUrl;

@JsonIgnore
protected String zookeeperPassword;

@JsonIgnore
protected Map<String, CreateContainerMetadata<?>> metadataMap;

@JsonIgnore
private CreationStateListener creationStateListener;

@Override
@JsonIgnore
public CreationStateListener getCreationStateListener() {
return null;
}

@Override
@JsonIgnore
public void setCreationStateListener(CreationStateListener creationStateListener) {

}
}
@@ -0,0 +1,34 @@
package io.hawt.jsonschema.mixins;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.hawt.jsonschema.api.MixInAnnotation;
import org.fusesource.fabric.api.CreateEnsembleOptions;
import org.fusesource.fabric.api.CreateRemoteContainerOptions;

/**
* @author Stan Lewis
*/
public class CreateContainerRemoteMixinOverrides implements MixInAnnotation {

@Override
public Class getMixinSource() {
return CreateRemoteContainerMixin.class;
}

@Override
public Class getTarget() {
return CreateRemoteContainerOptions.class;
}
}


interface CreateRemoteContainerMixin extends CreateRemoteContainerOptions {

@JsonIgnore
CreateEnsembleOptions getCreateEnsembleOptions();

@JsonIgnore
void setCreateEnsembleOptions(CreateEnsembleOptions createEnsembleOptions);


}

0 comments on commit 6d8a50f

Please sign in to comment.