In SpEL, create a new inline list using a previously-constructed list - spring

In spring-integration I'm wanting to "update" a list of values that are kept within a message header, using a header-enricher.
In my example, I've created an inline list {'x', 'y'} and I want to add 'z' to that list. I haven't found an example of how to do this in SpEL. It seems like it should be a common, trivial thing to do.
<si:header-enricher>
<si:header name="myList" expression="{ 'x', 'y' }" />
</si:header-enricher>
...
<si:header-enricher default-overwrite="true" >
<!-- CLEARLY THIS DOESN'T WORK BUT USING TO DEMONSTRATE THE DESIRED RESULT -->
<si:header name="myList" expression="{ headers.myList, 'z' }" />
</si:header-enricher>
How does one indicate that you want to create a new inline list that is the result of adding a value to an existing list?
In the demonstration code, the outcome would be [ [ 'x', 'y' ], 'z' ] rather than the desired ['x', 'y', 'z' ].
thanks for any pointers

This uses the Java DSL, but the expressions will work in XML too
#Bean
IntegrationFlow flow() {
return IntegrationFlows.fromSupplier(() -> "foo", e -> e.poller(Pollers.fixedDelay(Duration.ofSeconds(5))))
.enrichHeaders(headers -> headers
.headerExpression("list", "{ 'x', 'y' }"))
.enrichHeaders(headers -> headers
.headerExpression("list", "T(java.util.stream.Stream).concat(headers.list.stream(), "
+ "{ 'z' }.stream()).collect(T(java.util.stream.Collectors).toList())")
.defaultOverwrite(true))
.log()
.get();
}
Result:
GenericMessage [payload=foo, headers={list=[x, y, z], ...
EDIT
Here's another alternative:
public class MyList<T> extends ArrayList<T> {
public MyList(List<T> original, T... elements) {
super(original);
for (T element : elements) {
add(element);
}
}
}
Then "new com.example.demo.MyList(headers.list, 'z')"

For completeness, and in case it's interesting for someone else, I'm posting a solution using custom SpEL functions, recommended by #Artem.
Adding a static method into an abstract class for list concatenation:
package me.myself;
...
public abstract class MySpelFunctions {
public static <T> List<T> listConcat(Iterable<? extends T> a, Iterable<? extends T> b) {
return unmodifiableList(Lists.newArrayList(Iterables.concat(a, b)));
}
}
Then using the namespace support to add this custom function to the evaluation context:
<int:spel-function id="listConcat"
class="me.myself.MySpelFunctions"
method="listConcat(java.lang.Iterable, java.lang.Iterable)" />
We can now use the custom function within the SpEL expression for the header-enricher:
<si:header-enricher>
<si:header name="myList" expression="{ 'x', 'y' }" />
</si:header-enricher>
...
<si:header-enricher default-overwrite="true" >
<si:header name="myList" expression="#listConcat( headers.myList, { 'z' } )" />
</si:header-enricher>
Thanks again for your help in arriving at a readable solution.

Related

writing a typesafe visitor with labeled rules

I am migrating my prototype from a listener to a visitor pattern. In the prototype, I have a grammar fragment like this:
thingList: thing+ ;
thing
: A aSpec # aRule
| B bSpec # bRule
;
Moving to a visitor pattern, I am not sure how I write visitThingList. Every visitor returns a specializes subclass of "Node", and I would love somehow when to be able to write something like this, say a "thingList" cares about the first thing in the list some how ...
visitThingList(cx: ThingListContext): ast.ThingList {
...
const firstThing = super.visit(cx.thing(0));
The problem with this is in typing. Each visit returns a specialized type which is a subclass of ast.Node. Because I am using super.visit, the return value will be the base class
of my node tree. However, I know because I am looking at the grammar
and because I wrote both vistARule and visitBRule that the result of the visit will be of type ast.Thing.
So we make visitThingList express it's expectation with cast ...
visitThingList(cx: ThingListContext): ast.ThingList {
const firstThing = super.visit(cx.thing(0));
if (!firstThing instanceof ast.Thing) {
throw "no matching visitor for thing";
}
// firstThing is now known to be of type ast.Thing
...
In much of my translator, type problems with ast Nodes are a compile time issue, I fix them in my editor. In this case, I am producing a more fragile walk, which will only reveal the fragility at runtime and then only with certain inputs.
I think I could change my grammar, to make it possible to encode the
type expectations of vistThingList() by creating a vistThing() entry point
thingList: thing+ ;
thing: aRule | bRule;
aRule: A aSpec;
bRule: B bSpec;
With vistThing() typed to match the expectation:
visitThing(cx: ThingContext): ast.Thing { }
visitThingList(cx: ThingListContext) {
const firstThing: ast.Thing = this.visitThing(cx.thing(0));
Now visitThingList can call this.visitThing() and the type enforcement of making sure all rules that a thing matches return ast.Thing belongs to visitThing(). If I do create a new rule for thing, the compiler will force me to change the return type of visitThing() and if I make it return something which is NOT a thing, visitThingList() will show type errors.
This also seems wrong though, because I don't feel like I should have to change my grammar in order to visit it.
I am new to ANTLR and wondering if there is a better pattern or approach to this.
When I was using the listener pattern, I wrote something like:
enterThing(cx: ThingContext) { }
enterARule(cx : ARuleContext) { }
enterBRule(cx : BRuleContext) { }
Not quite: for a labeled rule like thing, the listener will not contain enterThing(...) and exitThing(...) methods. Only the enter... and exit... methods for the labels aSpec and bSpec will be created.
How would I write the visitor walk without changing the grammar?
I don't understand why you need to change the grammar. When you keep the grammar like you mentioned:
thingList: thing+ ;
thing
: A aSpec # aRule
| B bSpec # bRule
;
then the following visitor could be used (again, there is no visitThing(...) method!):
public class TestVisitor extends TBaseVisitor<Object> {
#Override
public Object visitThingList(TParser.ThingListContext ctx) {
...
}
#Override
public Object visitARule(TParser.ARuleContext ctx) {
...
}
#Override
public Object visitBRule(TParser.BRuleContext ctx) {
...
}
#Override
public Object visitASpec(TParser.ASpecContext ctx) {
...
}
#Override
public Object visitBSpec(TParser.BSpecContext ctx) {
...
}
}
EDIT
I do not know how, as i iterate over that, to call the correct visitor for each element
You don't need to know. You can simply call the visitor's (super) visit(...) method and the correct method will be invoked:
class TestVisitor extends TBaseVisitor<Object> {
#Override
public Object visitThingList(TParser.ThingListContext ctx) {
for (TParser.ThingContext child : ctx.thing()) {
super.visit(child);
}
return null;
}
...
}
And you don't even need to implement all methods. The ones you don't implement, will have a default visitChildren(ctx) in them, causing (as the name suggests) all child nodes under them being traversed.
In your case, the following visitor will already cause the visitASpec and visitBSpec being invoked:
class TestVisitor extends TBaseVisitor<Object> {
#Override
public Object visitASpec(TParser.ASpecContext ctx) {
System.out.println("visitASpec");
return null;
}
#Override
public Object visitBSpec(TParser.BSpecContext ctx) {
System.out.println("visitBSpec");
return null;
}
}
You can test this (in Java) like this:
String source = "... your input here ...";
TLexer lexer = new TLexer(CharStreams.fromString(source));
TParser parser = new TParser(new CommonTokenStream(lexer));
TestVisitor visitor = new TestVisitor();
visitor.visit(parser.thingList());

Is there a way to print out the chain of all operations in a Flux?

Given a Flux or a Mono from project reactor is a there a way to get the Flux or Mono to print out what the operator chain looks like. For example given the code below.
Fulx flux = Flux.just("a","b","c")
.map( v -> v.toUpperCase())
.log();
Is there some way to get the flux to print out a list of all the operators that are chained inside in the processing pipeline? Some nice ascii formatted text or a marble diagram?
printTheFlux(flux) should make a nice printout that show the structure of all the operators from the example above. I am not expecting to produce the code in the lambda's just a way to see what operators are chained together.
There is partial building blocks for doing this with the Scannable interface:
public String textRepresentation(Flux<?> flux) {
Scannable sc = Scannable.from(flux);
//scan the last operator in the chain and ask if it knows its parents
List<String> names = sc.parents().map(Scannable::operatorName)
.collect(Collectors.toList());
//as it traverses the chain from bottom to top, we need to reverse the order
Collections.reverse(names);
//need to also add the last operator
names.add(sc.operatorName());
return names.toString();
}
#Test
public void textRepresentationTest() {
Flux flux = Flux.just("a","b","c")
.map( v -> v.toUpperCase())
.log();
System.out.println(textRepresentation(flux));
}
Prints
[map, log]
Not all operators fully support it though (as you can see, the just source doesn't for instance).
Nice suggestion!
However, waiting for it, we can just have something like :
Disposable flux = Flux.just("a", "b", "c")
.map(String::toUpperCase)
.doOnNext(FluxUtil::print)
.subscribe();
Where FluxUtil::print is just a static method that you can write with different ways.
Here is the complete code works for me:
public class FluxUtil {
private static String s = "";
public static void main(String[] args) {
Disposable flux = Flux.just("a", "b", "c")
.map(String::toUpperCase)
.doOnNext(FluxUtil::print)
.subscribe();
}
private static Object print(Object o) {
s = !s.isEmpty() ? s.concat("->") : s;
s = s.concat(o.toString());
System.out.println(s);
return o;
}
}

Using org.xmlunit.diff.NodeFilters in XMLUnit DiffBuilder

I am using the XMLUnit in JUnit to compare the results of tests. I have a problem wherein there is an Element in my XML which gets the CURRENT TIMESTAMP as the tests run and when compared with the expected output, the results will never match.
To overcome this, I read about using org.xmlunit.diff.NodeFilters, but do not have any examples on how to implement this. The code snippet I have is as below,
final org.xmlunit.diff.Diff documentDiff = DiffBuilder
.compare(sourcExp)
.withTest(sourceActual)
.ignoreComments()
.ignoreWhitespace()
//.withNodeFilter(Node.ELEMENT_NODE)
.build();
return documentDiff.hasDifferences();
My problem is, how do I implement the NodeFilter? What parameter should be passed and should that be passed? There are no samples on this. The NodeFilter method gets Predicate<Node> as the IN parameter. What does Predicate<Node> mean?
Predicate is a functional interface with a single test method that - in the case of NodeFilter receives a DOM Node as argument and returns a boolean. javadoc of Predicate
An implementation of Predicate<Node> can be used to filter nodes for the difference engine and only those Nodes for which the Predicate returns true will be compared. javadoc of setNodeFilter, User-Guide
Assuming your element containing the timestamp was called timestamp you'd use something like
.withNodeFilter(new Predicate<Node>() {
#Override
public boolean test(Node n) {
return !(n instanceof Element &&
"timestamp".equals(Nodes.getQName(n).getLocalPart()));
}
})
or using lambdas
.withNodeFilter(n -> !(n instanceof Element &&
"timestamp".equals(Nodes.getQName(n).getLocalPart())))
This uses XMLUnit's org.xmlunit.util.Nodes to get the element name more easily.
The below code worked for me,
public final class IgnoreNamedElementsDifferenceListener implements
DifferenceListener {
private Set<String> blackList = new HashSet<String>();
public IgnoreNamedElementsDifferenceListener(String... elementNames) {
for (String name : elementNames) {
blackList.add(name);
}
}
public int differenceFound(Difference difference) {
if (difference.getId() == DifferenceConstants.TEXT_VALUE_ID) {
if (blackList.contains(difference.getControlNodeDetail().getNode()
.getParentNode().getNodeName())) {
return DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
}
}
return DifferenceListener.RETURN_ACCEPT_DIFFERENCE;
}
public void skippedComparison(Node node, Node node1) {
}

Representing enum variants with optional data in macro_rules

I'm trying to create a macro to help with some boilerplate enum code that I've been repetitively writing. I managed to implement a simple enum (i.e. no arguments) relatively easily using a basic macro_rule. e.g. An excerpt:
macro_rules! enum_helper {
($type:ident, { $( $name:ident ), * }) => {
enum $type {
$(
$name,
)+
}
impl FromSql for $type {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<&type> {
// ... the implementation
}
// ... plus some other internal traits being implemented
}
}
enum_helper!(Step, {
Step1,
Step2
});
I was hoping to extend this macro to also support a mixed set of enum styles, primarily with only one typed argument e.g.
enum_helper!(Step, {
Step1,
Step2,
Step3(i64)
});
Is there a way to represent this "optional" argument using macro_rules? I suspect it involves using a tt however I'm still a bit lost with how tt works in a subnested environment.
Update 1
I'm using $name within some of the trait implementations for pattern matching. For example, I have some code similar to below:
match raw {
$(
$type::$name => { /* a result of some sort */ },
)+
}

Xtext custom validator warning - How to mark keyword?

I have the simple Greeting example in xtext. So the DSL is defined like this:
grammar org.xtext.example.mydsl.Tests with org.eclipse.xtext.common.Terminals
generate tests "http://www.xtext.org/example/mydsl/Tests"
Model:
greetings+= Greeting*;
Greeting:
'Hello' name=ID '!';
Moreover, I have the following validator:
#Check
def checkGreetingStartsWithCapital(Greeting greeting) {
if (!Character.isUpperCase(greeting.name.charAt(0))) {
warning('Name should start with a capital',
TestsPackage.Literals.GREETING__NAME,
-1,
INVALID_NAME)
}
}
If I write the validator like this and have an expression like
"Hello world!"
in my model, the "world" is marked, i.e. there is this yellow line under it. What do I have to do if I want to mark only the keyword so in this case only the "Hello"?
I tried quite a few things and I can only manage to either mark the whole line "Hello world!" or just the "world".
Thank you!
have a look at the other methods for reporting a warning/error. there is one that takes an offset and length. you can use the node model to get them for the keyword
class MyDslValidator extends AbstractMyDslValidator {
public static val INVALID_NAME = 'invalidName'
#Inject extension MyDslGrammarAccess
#Check
def checkGreetingStartsWithCapital(Greeting greeting) {
if (!Character.isUpperCase(greeting.name.charAt(0))) {
val node = NodeModelUtils.findActualNodeFor(greeting)
for (n : node.asTreeIterable) {
val ge = n.grammarElement
if (ge instanceof Keyword && ge == greetingAccess.helloKeyword_0) {
messageAcceptor.acceptWarning(
'Name should start with a capital',
greeting,
n.offset,
n.length,
INVALID_NAME
)
}
}
}
}
}
I found another very simple solution I haven't thought of that includes changing the DSL a bit, i.e. add the keyword as a attribute.
Greeting:
keyword='Hello' name=ID '!';
Then the validator works as in the question:
#Check
def checkGreetingStartsWithCapital(Greeting greeting) {
if (!Character.isUpperCase(greeting.name.charAt(0))) {
warning('Name should start with a capital',
TestsPackage.Literals.GREETING__KEYWORD,
-1,
INVALID_NAME)
}
}

Resources