Having a map as a Maven plugin parameter - plugins

I am using maven 3 and I want to pass in a type Map as a parameter.
I have this in my mojo at the moment:
/**
* #parameter expression="${rep.env}" alias="environments"
* #required
*/
private Map<String,String[]> environments = null;
I am passing in this during the configuration:
<environments>
<Testing>
<param>
unit
</param>
</Testing>
</environments>
It is complaining that it is missing the parameter environments, are you allowed to do this in maven?

Did you try to just remove the alias="environments" attribute?
Another point is that I am not sure that Maven will allow you to set a Map of String[] as key. I think it will only deal with Map<String, String> (the page here only shows a basic Map example).
Eventually, what you can do is to allow comma-separated value instead of a String[]:
<configuration>
<environments>
<one>a,b,c</one>
<two>d</two>
</environments>
</configuration>
and then, when you have to deal with your values, you simply split your String to get a String array (you can use Apache Commons-lang StringUtils to do that easily):
/**
* #parameter expression="${rep.env}"
* #required
*/
private Map<String, String> environments = null;
public void foo() {
String[] values = StringUtils.split(environments.get("one"), ',');
// values == {"a", "b", "c"};
}

Related

Why does my AutoValueExtension annotation not work?

I have been trying to use Square's Redacted annotation to redact a pin from a toString() method in my auto generated class but the extension is not being applied. It seems like the extension is not read by the class loader.
The #AutoValue annotation works fine but the #Redacted annotation is not applied.
package io.*******.********.order.pin.hsm;
import com.google.auto.value.AutoValue;
import io.*****.crypto.model.PinBlockFormat;
#AutoValue
public abstract class GeneratePvvRequest {
/** #return Hexadecimal string representing the encrypted PIN */
#Redacted
public abstract String pinBlock();
/** #return Account number under which the PIN block is currently encrypted */
public abstract String pinBlockAccountNumber();
/** #return Name of the ZPK under which the PIN block is currently encrypted */
public abstract String zpkName();
/** #return Index of the ZPK under which the PIN block is currently encrypted */
public abstract Integer zpkIndex();
/** #return ISO format under which the PIN block is currently encrypted */
public abstract PinBlockFormat pinBlockFormat();
/** #return Account number used to generate the pin's PVV */
public abstract String pvvAccountNumber();
public static GeneratePvvRequest create(
String pinBlock,
String pinBlockAccountNumber,
String zpkName,
Integer zpkIndex,
PinBlockFormat pinBlockFormat,
String pvvAccountNumber) {
return new AutoValue_GeneratePvvRequest(
pinBlock,
pinBlockAccountNumber,
zpkName,
zpkIndex,
pinBlockFormat,
pvvAccountNumber);
}
}
I discovered my problem. I needed to add an annotationProcessorPath to the maven-compiler-plugin.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<annotationProcessorPaths>
<!-- Allow Dagger to generate its boilerplate -->
<path>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>${electrum.dependency.dagger.version}</version>
</path>
<!-- The below wasn't strictly required, but adding any entries under annotationProcessorPaths -->
<!-- overrides the default path which included the necessary annotation processor for auto-value -->
<path>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>${electrum.dependency.auto-value.version}</version>
</path>
<path>
<groupId>com.squareup.auto.value</groupId>
<artifactId>auto-value-redacted</artifactId>
<version>1.1.1</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Everything works hunky-dory now.

how to pass namedQuery parameters in Apache Camel JPA by header?

I have this camel route:
from("direct:getUser")
.pollEnrich("jpa://User?namedQuery=User.findById&consumeDelete=false");
This is my user Entity:
#Entity
#NamedQueries({
#NamedQuery(name="User.findAll", query="SELECT u FROM User u"),
#NamedQuery(name="User.findById", query="SELECT u FROM User u WHERE u.id = :id")
})
public class User{
#Id
private String id;
}
I have tried this route by setting the header:
from("direct:getUser")
.setHeader("id", simple("myid"))
.pollEnrich("jpa://User?namedQuery=User.findById&consumeDelete=false");
But it is not working
Is there any method to set jpa properties by the headers? The camel documentation quote this in parameters option but i don't found the examples
Options: parameters
This option is Registry based which requires the # notation. This
key/value mapping is used for building the query parameters. It is
expected to be of the generic type java.util.Map where
the keys are the named parameters of a given JPA query and the values
are their corresponding effective values you want to select for. Camel
2.19: it can be used for producer as well. When it's used for producer, Simple expression can be used as a parameter value. It
allows you to retrieve parameter values from the message body header
and etc.
I hope it's not too late to answer. In any case I had a similar issue in my project, the client does a HTTP GET with a parameter id, which is used by the JPA query and the result is finally marshalled back to the HTTP client. I'm running camel in a Spring application.
I finally figured out how to achieve it in a reasonably clean way.
This is the RouteBuilder where the route is defined:
#Override
public void configure() throws Exception {
Class dataClass = SomeClass.class;
JacksonDataFormat format = new JacksonDataFormat();
format.setUnmarshalType(dataClass);
String jpaString = String
.format("jpa://%1$s?resultClass=%1$s&namedQuery=q1" +
"&parameters={\"id\":${headers.id}}", dataClass.getName());
from("jetty://http://localhost:8080/test").toD(jpaString) // note the .toD
.marshal(format)
}
And this is the StringToMapTypeConverter class, otherwise camel cannot convert {"id": X} to a map
public class StringToMapTypeConverter implements TypeConverters {
private static final ObjectMapper mapper = new ObjectMapper();
private static JavaType mapType;
static {
mapType = mapper.getTypeFactory().constructMapType(Map.class,
String.class, Object.class);
}
#Converter
public Map<String, Object> toMap(String map) throws IOException {
return mapper.readValue(map, mapType);
}
}
Remember to add it to the context. In Spring is something like:
<bean id="myStringToMapTypeConverter" class="....StringToMapTypeConverter" />
Refs:
http://camel.apache.org/jpa.html
http://camel.apache.org/message-endpoint.html#MessageEndpoint-DynamicTo
http://camel.apache.org/type-converter.html#TypeConverter-Addtypeconverterclassesatruntime

update dynamically targeting provider in iPOJO

I have a component declared as:
<ipojo>
<component classname="HelloClass" name="helloCom" immediate="true">
<requires field="delayService" id="id1">
</requires>
</component>
<instance component="helloCom" name="hello">
<property name="requires.from">
<property name="id1" value="A"/>
</property>
</instance>
</ipojo>
The jar file of this component :helloComponent.jar
Now, i want to update (value="A") to (value="AA"). Thus, i implement a component using ConfigurationAdmin to update this property
public class ControllerReconfiguration {
private ConfigurationAdmin m_configAdmin;
#SuppressWarnings({ "rawtypes", "unchecked" })
public void reconfigure() throws IOException {
Configuration configuration = m_configAdmin.getConfiguration("hello","file:./helloComponent.jar");
configuration.setBundleLocation("file:./helloComponent.jar");
Properties props = new Properties();
//Dictionary props = new Hashtable();
props.put("id1", "AA");
configuration.update(props);
System.out.println("Update");
}
}
However, this ControllerReconfiguration component can't update the value 'A' (by 'AA') in 'hello' instance.
How to modify this ControllerReconfiguration component, please ?
Thanks you for your help.
Unfortunately, you can't push new 'from' configuration like this.
However, you can use the iPOJO introspection API directly: http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/ipojo-advanced-topics/using-ipojo-introspection-api.html
Retrieve the Architecture service of the instance
Retrieve the InstanceDescription and DependencyDescription
Call the setFilter method
Thanks Clement,
it works fine !!!!! :) I access InstanceManager using Factory.
Ex, in order to access InstanceManager of component "hello.call.CallHello"
#require
private Factory[] factories;
for (Factory factory : factories) {
/*
* "hello.call.CallHello" is a component name
* note: it is not component instance name
*/
if (factory.getName().equals("hello.call.CallHello")) {
/*
* a component can have many instances
* if there is only one instance.
* get(0) return the first instance.
*/
InstanceManager im = (InstanceManager) factory.getInstances().get(0);
}

How to add structural links to Jersey/Moxy/JAXB XML without altering the model

I mean "structural links" in the HATEOAS/hypermedia API sense. The more general question is how to augment the generated XML with data that depends on both the entity being marshalled, and also on the environment (in this case, at least the absolute URL).
I'm using Jersey 2.9 with Moxy 2.5 as the JAXB provider.
From this model:
package testing;
import java.util.ArrayList;
import java.util.List;
public class Planet {
private int id = 1;
private String name = "test";
private double radius = 3.0;
private String href;
private List<Moon> moons = new ArrayList<Moon>(0);
public void addMoon(Moon moon) {
moons.add(moon);
}
}
...plus Moon class
I want to get something like this XML (and the equivalent JSON):
<planet href="http://mytestserver/rest/planets/test">
<name>test</name>
<radius>3.0</radius>
<moons>
<moon href="http://mytestserver/rest/moons/moon1">
<name>moon1</name>
</moon>
<moon href="http://mytestserver/rest/moons/moon2">
<name>moon2</name>
</moon>
</moons>
</planet>
The model has no "href" field, nor can one be added. Ideally I could use UriBuilder to grab these paths straight from the resource classes.
So far I've come up with several possiblities. Can I ask you to consider which (if any) has the most legs, and then how you would work around the shortcomings of that method?
1. Augment the model with AspectJ (or Javassist).
And then use the existing declarative linking mechanisms in Jersey, all of which rely on there being a field in the model to receive the generated links. This obviously won't work if you don't have AspectJ in your build process and/or balk at exotic techniques like byte code manipulation.
2. Post-process the generated XML and JSON
For example, in a MessageBodyWriter:
ContextResolver<JAXBContext> resolver = providers.getContextResolver(JAXBContext.class, mediaType);
JAXBContext context = resolver.getContext(type);
Marshaller m = context.createMarshaller();
<--- here, marshall to e.g. a DOM then transform that
<--- then manipulate the JSON structures
I have absolutely no idea how to do any of that, hence the lack of code. There may be other ways to hook into the XML generation process, but as far as I can see none of Jersey's or JAXB's event handlers or interceptors actually allow you to manipulate the generated XML/JSON.
3. Use a Moxy XMLTransformationMapping
For example:
XML binding:
<java-type name="Planet" xml-customizer="testing.HrefCustomizer">
Customizer:
public class HrefCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
XMLTransformationMapping xtm = new XMLTransformationMapping();
xtm.addFieldTransformer("#href", new HrefWriter());
descriptor.addMapping(xtm);
}
}
Transformer:
public class HrefWriter implements FieldTransformer {
#Override
public Object buildFieldValue(Object instance, String fieldName,
Session session) {
return "href"; // constant value just for proof-of-concept
}
#Override
public void initialize(AbstractTransformationMapping mapping) {
// TODO Auto-generated method stub
}
}
I have two problems with this approach:
It was so hard to find any documentation on it that I wonder if it is in fact unsupported usage.
I can't see how the transformer is going to get a UriBuilder to work with. At minimum it would need the root URL of the rest service.
4. Slightly different Moxy xml-transform approach
If we decide we can't provide the transformer with any meaningful context at instantiation time, the customizer is adding no value and we can simplify the above to just this:
<java-type name="Planet">
<xml-root-element/>
<java-attributes>
<xml-transformation java-attribute="name">
<xml-write-transformer transformer-class="testing.HrefWriter" xml-path="#href"/>
</xml-transformation>
<xml-element java-attribute="name"/>
With the slight oddity that we are hanging the transformer off another field ("name", in this example).
5. ?????
Or, I'm completely barking up the wrong tree. Help!!
AspectJ approach
Synopsis
Use AspectJ to add a field to the model classes (called "href" in this example)
Add the Jersey #InjectLink annotation to that field
Jersey will then populate the field with the right URL as defined by the resource class
Specify the marshaling of the href field using an external mapping file.
You could also specify the marshaling of href by adding JAXB annotations to it via the same AspectJ intertype declaration mechanism.
Example code
These are the most informative bits. See http://lagod.id.au/blog/?p=494 for the full example.
The aspect
package testing;
import org.glassfish.jersey.linking.InjectLink;
import org.glassfish.jersey.linking.Binding;
public aspect HrefInjector {
private String Planet.href;
declare #field : * Planet.href : #InjectLink(
resource=Services.class,
style=InjectLink.Style.ABSOLUTE
) ;
private String Moon.href;
declare #field : * Moon.href : #InjectLink(
resource=Services.class,
method="moon",
bindings={#Binding(
name="moonid", value="${instance.name}"
)},
style=InjectLink.Style.ABSOLUTE
) ;
}
Model classes
POJOs with no REST-specific cruft. See Jersey + Moxy + JAXB - how to marshal XML without annotations.
package testing;
import java.util.ArrayList;
import java.util.List;
public class Planet {
private int id = 1;
private String name = "test";
private double radius = 3.0;
private List<Moon> moons = new ArrayList<Moon>(0);
public void addMoon(Moon moon) {
moons.add(moon);
}
}
package testing;
public class Moon {
private String name;
// No-arg constructor is a requirement of JAXB
public Moon() {
}
public Moon(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Resource class
This is a standard JAX-RS resource class. For demo purposes, we're just returning freshly instantiated model instances.
package testing;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/services")
#Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public class Services {
private Planet initPlanet() {
Planet p = new Planet();
p.addMoon(new Moon("moon1"));
p.addMoon(new Moon("moon2"));
return p;
}
#GET
public Planet planet () {
return initPlanet();
}
#GET #Path("/moons/{moonid}")
public Moon moon (#PathParam("moonid") String name) {
return new Moon(name);
}
}
Moxy mapping file
Note that you can choose for any given type whether or not you want to actually marshal the href field. In fact, by using multiple mapping files, you can include the href field in some representations and not in others.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="testing"
xml-mapping-metadata-complete="true"
xml-accessor-type="NONE">
<java-types>
<java-type name="Planet">
<xml-root-element/>
<java-attributes>
<xml-attribute java-attribute="href"/>
<xml-element java-attribute="name"/>
<xml-element java-attribute="radius"/>
<xml-element java-attribute="moons" name="moon">
<xml-element-wrapper name="moons"/>
</xml-element>
</java-attributes>
</java-type>
<java-type name="Moon">
<xml-root-element/>
<java-attributes>
<xml-attribute java-attribute="href"/>
<xml-element java-attribute="name"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Sample output
Ta-dah! Structural links derived automatically from the JAX-RS resource class without altering model source code. Because we're using Moxy, we also get JSON for free.
<planet href="http://localhost:8080/reststructlinks/rest/services">
<name>test</name>
<radius>3.0</radius>
<moons>
<moon href="http://localhost:8080/reststructlinks/rest/services/moons/moon1">
<name>moon1</name>
</moon>
<moon href="http://localhost:8080/reststructlinks/rest/services/moons/moon2">
<name>moon2</name>
</moon>
</moons>
</planet>

javax.ws.rs.core.PathSegment and Errai

Errai has support for JAX-RS, although when I tried to use it with the supplied Maven archetype GWT complained with the error:
No source code is available for type javax.ws.rs.core.PathSegment; did you forget to inherit a required module?
The PathSegment interface appears to be part of the official Java EE standard, so why is this class not available?
A solution is to create the javax.ws.rs.core package in your GWT project, and include the interfaces for yourself. These interfaces are MultivaluedMap:
package javax.ws.rs.core;
import java.util.List;
import java.util.Map;
/**
* A map of key-values pairs. Each key can have zero or more values.
*
*/
public interface MultivaluedMap<K, V> extends Map<K, List<V>> {
/**
* Set the key's value to be a one item list consisting of the supplied value.
* Any existing values will be replaced.
*
* #param key the key
* #param value the single value of the key
*/
void putSingle(K key, V value);
/**
* Add a value to the current list of values for the supplied key.
* #param key the key
* #param value the value to be added.
*/
void add(K key, V value);
/**
* A shortcut to get the first value of the supplied key.
* #param key the key
* #return the first value for the specified key or null if the key is
* not in the map.
*/
V getFirst(K key);
}
PathSegment:
package javax.ws.rs.core;
/**
* Represents a URI path segment and any associated matrix parameters. When an
* instance of this type is injected with {#link javax.ws.rs.PathParam}, the
* value of the annotation identifies which path segment is selected and the
* presence of an {#link javax.ws.rs.Encoded} annotation will result in an
* instance that supplies the path and matrix parameter values in
* URI encoded form.
*
* #see UriInfo#getPathSegments
* #see javax.ws.rs.PathParam
*/
public interface PathSegment
{
/**
* Get the path segment.
* <p/>
*
* #return the path segment
*/
String getPath();
/**
* Get a map of the matrix parameters associated with the path segment.
* The map keys are the names of the matrix parameters with any
* percent-escaped octets decoded.
*
* #return the map of matrix parameters
* #see Matrix URIs
*/
MultivaluedMap<String, String> getMatrixParameters();
}
You'll need a GWT module file (in the javax.ws.rs package):
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6//EN"
"http://google-web-toolkit.googlecode.com/svn/releases/1.6/distro-source/core/src/gwt-module.dtd">
<module rename-to="App">
<source path="core"/>
</module>
And you'll need to add an inherits reference to you application GWT module:
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6//EN"
"http://google-web-toolkit.googlecode.com/svn/releases/1.6/distro-source/core/src/gwt-module.dtd">
<module rename-to="App">
<inherits name='com.google.gwt.user.User'/>
<inherits name="org.jboss.errai.common.ErraiCommon"/>
<inherits name="org.jboss.errai.ioc.Container"/>
<inherits name="org.jboss.errai.enterprise.Jaxrs"/>
<inherits name="com.redhat.topicindex.rest"/>
<inherits name="javax.ws.rs.core"/>
</module>