How to trust all packages when deserialising in Spring Cloud Stream? - spring-kafka

This consumer didn't need trusted packages:
#Bean
fun berichtStateStoreBuilder() = Consumer<GlobalKTable<String, BerichtEvent>> {}
This suddenly does:
#Bean
fun berichtStateStoreBuilder() = Consumer<KStream<ByteArray, ByteArray>> {
it
.transform({ EventTypeAwareTransformer(EVENT_TYPE_MAPPING, objectMapper) })
.mapValues { v -> v.payload as BerichtEvent }
.groupByKey(Grouped.with(Serdes.StringSerde(), JsonSerde()))
.aggregate(
{ BerichtAggregator() },
{ _, event, aggregator -> aggregator.add(event) },
Named.`as`("aggregate"),
Materialized.`as`<String, BerichtAggregator, KeyValueStore<Bytes, ByteArray>>(BerichtStore.NAME)
.withKeySerde(Serdes.String())
.withValueSerde(JsonSerde(BerichtAggregator::class.java))
)
I've tried the following approaches, but they didn't work as I only get the following error:
Caused by: java.lang.IllegalArgumentException: The class 'at.wrwks.smp.controlling.event.BerichtEvent' is not in the trusted packages: [java.util, java.lang]. If you believe this class is safe to deserialize, please provide its name. If the serialization is only done by a trusted source, you can also enable trust all (*).
at org.springframework.kafka.support.converter.DefaultJackson2JavaTypeMapper.getClassIdType(DefaultJackson2JavaTypeMapper.java:126)
at org.springframework.kafka.support.converter.DefaultJackson2JavaTypeMapper.toJavaType(DefaultJackson2JavaTypeMapper.java:100)
at org.springframework.kafka.support.serializer.JsonDeserializer.deserialize(JsonDeserializer.java:504)
at org.apache.kafka.streams.processor.internals.SourceNode.deserializeValue(SourceNode.java:55)
at org.apache.kafka.streams.processor.internals.RecordDeserializer.deserialize(RecordDeserializer.java:66)
... 8 more
#Bean
fun defaultKafkaHeaderMapper(objectMapper: ObjectMapper): DefaultKafkaHeaderMapper {
val mapper = DefaultKafkaHeaderMapper(objectMapper, "event_type")
val rawMappedHeaders = HashMap<String, Boolean>()
rawMappedHeaders[BaseEvent.EVENT_TYPE_HEADER] = true
mapper.setRawMappedHeaders(rawMappedHeaders)
mapper.addTrustedPackages("*")
return mapper
}
spring.cloud.stream.kafka.streams.binder.header-mapper-bean-name: defaultKafkaHeaderMapper
spring.cloud.stream.kafka.streams.binder.configuration.spring.json.use.type.headers: false
spring.cloud.stream.kafka.streams.binder.configuration.spring.json.trusted.packages: '*'
Spring Cloud Stream version: 3.1.2 with Kafka Streams binder.
Workaround by using a custom JSON serde:
.groupByKey(Grouped.with(Serdes.StringSerde(), Serdes.serdeFrom(
SimpleJsonSerializer(objectMapper), SimpleJsonDeserializer(objectMapper, BerichtEvent::class.java)
)))

I just tested it and it works fine for me...
#SpringBootApplication
public class So67059860Application {
public static void main(String[] args) {
SpringApplication.run(So67059860Application.class, args);
}
#Bean
public Consumer<KStream<String, Foo>> input() {
return str -> str.foreach((k, v) -> System.out.println(v));
}
}
public class Foo {
private String bar;
public String getBar() {
return this.bar;
}
public void setBar(String bar) {
this.bar = bar;
}
#Override
public String toString() {
return "Foo [bar=" + this.bar + "]";
}
}
spring.cloud.stream.kafka.streams.binder.configuration.default.value.serde=org.springframework.kafka.support.serializer.JsonSerde
spring.cloud.stream.kafka.streams.binder.configuration.spring.json.trusted.packages=*
spring.cloud.stream.kafka.streams.binder.configuration.spring.json.value.default.type=com.example.demo.Foo
spring.application.name=so67059860
spring.cloud.function.definition=input
#logging.level.root=debug
Foo [bar=baz]
Boot 2.4.4, Cloud 2020.0.2 (SCSt 3,1.2).
Set a breakpoint in JsonSerde.configure() to see the properties being used.

Although I've done this dozens of times this time I forgot to pass the target class to the constructor JsonSerde(). This is correct:
.groupByKey(Grouped.with(Serdes.StringSerde(), JsonSerde(BerichtEvent::class.java)))
Apparently when no class will be passed, then no package can be added to the trusted packages. With a class passed the Serde will be configured with the package the target pass belongs to.

Related

NativeActivity in XAML loaded COMPILED workflow throws Expression Activity type 'CSharpValue1' requires compilation in order to run

This is a know error when using C# expressions in windows workflow. The article at https://learn.microsoft.com/en-us/dotnet/framework/windows-workflow-foundation/csharp-expressions#CodeWorkflows explains the reason and how to fix it. It all works fine for me in standard workflows, but as soon as I add a custom NativeActivity to the WF, I get that same error again !
Below the code of how I load the XAML workflow and the simple NativeActivity (which is the ONLY activity in the test workflow and inside that activity is a simple assign expression).
Loading and invoking WF via XAML:
`XamlXmlReaderSettings settings = new XamlXmlReaderSettings()
{
LocalAssembly = GetContextAssembly()
};
XamlReader reader = reader = ActivityXamlServices.CreateReader(new XamlXmlReader(fileURL, settings));
ActivityXamlServicesSettings serviceSettings = new ActivityXamlServicesSettings
{
CompileExpressions = true
};
var activity = ActivityXamlServices.Load(reader, serviceSettings);
WorkflowInvoker.Invoke(activity);`
Doing it in code throws same Exception:
Variable<string> foo = new Variable<string>
{
Name = "Foo"
};
Activity activity = new Sequence
{
Variables = { foo },
Activities =
{
new TimeExecuteUntilAborted
{
Activities =
{
new Assign<string>
{
To = new CSharpReference<string>("Foo"),
Value = new CSharpValue<string>("new Random().Next(1, 101).ToString()")
}
}
}
}
};
CompileExpressions(activity);//the method from the article mentioned above
WorkflowInvoker.Invoke(activity);
The Native Activity:
[Designer("System.Activities.Core.Presentation.SequenceDesigner, System.Activities.Core.Presentation")]
public sealed class TimeExecuteUntilAborted : NativeActivity
{
private Sequence innerSequence = new Sequence();
[Browsable(false)]
public Collection<Activity> Activities
{
get
{
return innerSequence.Activities;
}
}
[Browsable(false)]
public Collection<Variable> Variables
{
get
{
return innerSequence.Variables;
}
}
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
metadata.AddImplementationChild(innerSequence);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(innerSequence);
}
}
Your TimeExecutedUntilAborted class seems to be the culprit. I was able to swap in one of my own template NativeActivities instead and your workflow executed fine with the expressions. I'm guessing that your class is causing an issue in the compiler method when it parses your code. I used this doc as an example for my NativeActivity: https://msdn.microsoft.com/en-us/library/system.activities.nativeactivity(v=vs.110).aspx.
Sizzle Finger's answer is no solution but pointed me into the right direction to simply check what is different. It came out that the simple call to the base class method was missing:
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
base.CacheMetadata(metadata); // !! This needs to be added
metadata.AddImplementationChild(innerSequence);
}

Registering cascading dependencies (Take 2)

I attempted to ask this question yesterday and failed completely to make sense. So I've built a reproduction to demonstrate my problem.
In the following program I am resolving Bar witch should have a Foo and a Fool injected into it. Fool also has a Foo injected into it. The catch is I want Bar and Fool to both use the same Foo. In the following code that is not happening.
class Program
{
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
Console.WriteLine("Resolving Bar");
container.Resolve<Bar>();
Console.ReadLine();
}
}
public class Foo
{
public Foo()
{
Console.WriteLine("Foo created " + this.GetHashCode());
}
}
public class Fool
{
public Foo Foo { get; set; }
public Fool(Foo foo)
{
Foo = foo;
Console.WriteLine("Fool created with injected Foo " + foo.GetHashCode());
}
}
public class Bar
{
public Bar(Foo foo, Fool fool)
{
Console.WriteLine("Bar created with injected Foo " + foo.GetHashCode());
Console.WriteLine("Bar created with injected Fool.Foo " + fool.Foo.GetHashCode());
// I want foo == fool.Foo
}
}
public class Blat
{
public Blat(Foo foo, Fool fool)
{
Console.WriteLine("Blat created with injected Foo " + foo.GetHashCode());
Console.WriteLine("Blat created with injected Fool.Foo " + fool.Foo.GetHashCode());
}
}
I could Resolve the types and define the a specific injection constructor in the Main method, but I have a complication. In this case I also create a Blat as well as a Bar. The catch is I want the Blat and the Bar to use different Foo's.
Consider:
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
var foo = container.Resolve<Foo>();
container.RegisterType<Fool>(new InjectionConstructor(foo));
var fool = container.Resolve<Fool>();
container.RegisterType<Bar>(new InjectionConstructor(foo, fool));
container.RegisterType<Blat>(new InjectionConstructor(foo, fool));
Console.WriteLine("Resolving Bar");
container.Resolve<Bar>();
container.Resolve<Blat>();
Console.ReadLine();
}
}
In this case Bar.Foo == Bar.Fool.Foo but Blat.Foo == Bar.Foo. In other words I want
Bar.Foo == Bar.Fool.Foo && Blat.Foo != Bar.Foo
Is there a way to do this? I will be resolving many types of Bar's and Blat's so I would like to avoid creating child containers for each Bar, Blat, etc...
EDITTED TO FURTHER CONFUSE THE ISSUE
The problem is in the real world I have something like the following:
BaseViewModel(Context context, ServiceA a, ServiceB b)
Each control will need a ViewModel created that uses a different context. In each viewModel the services have to use the same context. So I want Unity to create context, a, and b all using the same context.
I could do something similar to what you suggest. I could set a Context property on the services in the constructor of BaseViewModel, but that seems odd to me. Right now I'm just newing up the services in the constructor, but I'd rather do it with Unity so they aren't coupled so tightly. I was hoping there was a more elegant way.
With your IUnityContainer, register Foo with a PerResolveLifetimeManager, i.e.:
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.RegisterType<Foo>(new PerResolveLifetimeManager());
Console.WriteLine("Resolving Bar");
container.Resolve<Bar>();
container.Resolve<Blat>();
Console.ReadLine();
}
When you resolve Bar, the same instance of Foo will be injected into Bar and injected into Fool.
Then when you resolve Blat, a new instance of Foo will be injected into Blat and into Fool.
So Bar.Foo == Bar.Fool.Foo and Blat.Foo == Blat.Fool.Foo but Bar.Foo != Blat.Foo and Bar.Fool.Foo != Blat.Fool.Foo.
Every time you call container.Resolve, only one instance of Foo is ever resolved for that graph, that is what PerResolveLifetimeManager does.
Have you ever considered something like this:
public class Bar
{
public Bar(Fool fool)
{
this.Fool = fool;
}
public Foo Foo
{
get { return this.Fool.Foo; }
set { this.Fool.Foo = value; }
}
public Fool Fool { get; set; }
}
where Bar.Foo is just a convenience setter/getter for Bar.Fool.Foo? Why inject the same instance twice?

How can I enable logging in NVelocity?

Any idea how to do what the title says? Only thing I found was on the original Velocity site, and I don't think
ve.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
"org.apache.velocity.runtime.log.Log4JLogChute" );
ve.setProperty("runtime.log.logsystem.log4j.logger",
LOGGER_NAME);
will work wonderfully well on .NET. I am using log4net, which should make it quite easy, but the documentation on NVelocity is really a mess.
Implement NVelocity.Runtime.Log.ILogSystem (you could write a simple implementation that bridges to log4net) and set this impl type in the property RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS
How I got this information:
Get the code.
Search for "log" in the codebase
Discover the classes in NVelocity.Runtime.Log.
Read those classes' source, they're very simple and thoroughly documented.
Update:
Currently, NVelocity does not support logging. The initializeLogger() and Log() methods in RuntimeInstance Class are commented out.
If you need to log, uncomment the two methods, add a private ILogSystem logSystem; property
Here's our on-the-fly implementation:
public class RuntimeInstance : IRuntimeServices
{
private ILogSystem logSystem;
...
...
private void initializeLogger()
{
logSystem = LogManager.CreateLogSystem(this);
}
...
...
private void Log(LogLevel level, Object message)
{
String output = message.ToString();
logSystem.LogVelocityMessage(level, output);
}
...
}
Then, we implemented ILogSystem for log4net
using log4net;
using NVelocity.Runtime;
using NVelocity.Runtime.Log;
namespace Services.Templates
{
public class Log4NetILogSystem : ILogSystem
{
private readonly ILog _log;
public Log4NetILogSystem(ILog log )
{
_log = log;
}
public void Init(IRuntimeServices rs)
{
}
public void LogVelocityMessage(LogLevel level, string message)
{
switch (level)
{
case LogLevel.Debug:
_log.Debug(message);
break;
case LogLevel.Info:
_log.Info(message);
break;
case LogLevel.Warn:
_log.Warn(message);
break;
case LogLevel.Error:
_log.Error(message);
break;
}
}
}
}
Then, when creating the engine:
var engine = new VelocityEngine();
var props = new ExtendedProperties();
props.SetProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM,
new Log4NetILogSystem(LogManager.GetLogger(typeof(NVelocityEngine))));
engine.Init(props);

PureMVC / complicated asMock

Ok - I've got a bit of a complicated asMock setup here; I've got a PureMVC async command that is attempting to call another class that implements interfaces in order to set up some asmocks for development without the backend.
import test.mix.common.business.MockInterbahnServiceFactory;
public class InitMockInterbahnServiceFactory extends AsyncCommand{
public static var mockServiceFactory:MockInterbahnServiceFactory = new MockInterbahnServiceFactory();
override public function execute(notification:INotification):void{
var serviceResult:IEventDispatcher = mockServiceFactory.mockRepository.prepare([EchoBusinessObjects, SendBusinessObjects]);
//serviceResult.addEventListener(Event.COMPLETE, onComplete);
}
private function onComplete(event:Event):void{
mx.controls.Alert.show("COMPLETE!");
var logMessage:String = "4 MOCK SERVICE FACTORY MOCKED !!!!!";
sendNotification( MixConstants.LOG_OUTPUT, logMessage );
//sendNotification(MixConstants.INTERBAHN_CONNECTED, mockServiceFactory);
// commandComplete() ;
}
}
This is actually trying to set up a MockRepositoryFactory:
public class MockInterbahnServiceFactory implements ServiceFactory
{
[Mock] public static var withMocks : Array = [
SendBusinessObjects, EchoBusinessObjects
];
//public static var mockRepository:MockRepository ;//= new MockRepository();
public var mockSendBusinessObjects:SendBusinessObjects;
public var mockEchoBusinessObjects:EchoBusinessObjects ;
public var mockRepository:MockRepository;
public function MockInterbahnServiceFactory(){
mockRepository = new MockRepository();
prepareMocks();
}
public function prepareMocks():void{
var prepareDispatcher:IEventDispatcher = mockRepository.prepare([SendBusinessObjects, EchoBusinessObjects]);
prepareDispatcher.addEventListener(Event.COMPLETE, setupMocks);
}
public function setupMocks(event:Event):void{
mockSendBusinessObjects = SendBusinessObjects(mockRepository.create(SendBusinessObjects));
mockEchoBusinessObjects = EchoBusinessObjects(mockRepository.create(EchoBusinessObjects));
SetupResult.forCall(mockSendBusinessObjects.sendOrder(new Order())).returnValue('wee');
}
public function createSendBusinessObjectService():SendBusinessObjects{
return mockSendBusinessObjects;
}
public function createEchoBusinessObjectService():EchoBusinessObjects{
return mockEchoBusinessObjects;
}
}
}
And at some point this factory is going to get passed around and utilized for the send / receive endpoints for multiple communications (true backend being a scala one).
I'm getting this error:
ArgumentError: returnValue must be assignable from :void
at asmock.framework.expectations::AbstractExpectation/set returnValue()[C:\Users\Richard\SVN\asmock\trunk\source\ASMock\src\asmock\framework\expectations\AbstractExpectation.as:107]
at asmock.framework::MethodOptions/returnValue()[C:\Users\Richard\SVN\asmock\trunk\source\ASMock\src\asmock\framework\MethodOptions.as:134]
at test.mix.common.business::MockInterbahnServiceFactory/setupMocks()[/Users/grimm/Documents/__WORK/__INVESTLAB/MIX/trunk/src/test/mix/common/business/MockInterbahnServiceFactory.as:56]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at Function/org.floxy:ProxyRepository/org.floxy:IProxyRepository:prepare/org.floxy:swfLoadedHandler()[C:\transfer\IdeaProjects\as3-interbahn\floxy\main\as3\src\org\floxy\ProxyRepository.as:218]
I'm assuming this is because of the interface functions I'm stubbing?
public interface SendBusinessObjects {
function sendFirmExchangePermission(frp:FirmExchangePermission):void ;
function sendFirm(f:Firm):void ;
function sendExchange(ex:Exchange):void ;
function sendFXConversion(fx:FXConversion):void ;
function sendInstrument(ins:Instrument):void ;
function sendQuote(q:Quote):void ;
It looks to me like SendBusinessObjects returns void, but you are calling returnValue when you are mocking the call to it. Remove the returnValue('wee') call and it should work as expected.

Dynamically implement interface in Groovy using invokeMethod

Groovy offers some really neat language features for dealing with and implementing Java interfaces, but I seem kind of stuck.
I want to dynamically implement an Interface on a Groovy class and intercept all method calls on that interface using GroovyInterceptable.invokeMethod. Here what I tried so far:
public interface TestInterface
{
public void doBla();
public String hello(String world);
}
import groovy.lang.GroovyInterceptable;
class GormInterfaceDispatcher implements GroovyInterceptable
{
def invokeMethod(String name, args) {
System.out.println ("Beginning $name with $args")
def metaMethod = metaClass.getMetaMethod(name, args)
def result = null
if(!metaMethod)
{
// Do something cool here with the method call
}
else
result = metaMethod.invoke(this, args)
System.out.println ("Completed $name")
return result
}
TestInterface getFromClosure()
{
// This works, but how do I get the method name from here?
// I find that even more elegant than using invokeMethod
return { Object[] args -> System.out.println "An unknown method called with $args" }.asType(TestInterface.class)
}
TestInterface getThisAsInterface()
{
// I'm using asType because I won't know the interfaces
// This returns null
return this.asType(TestInterface.class)
}
public static void main(String[] args)
{
def gid = new GormInterfaceDispatcher()
TestInterface ti = gid.getFromClosure()
assert ti != null
ti.doBla() // Works
TestInterface ti2 = gid.getThisAsInterface()
assert ti2 != null // Assertion failed
ti2.doBla()
}
}
Returning the Closure works fine, but I couldn't figure a way to find out the name of the method being called there.
Trying to make a Proxy to the this reference itself (so that method calls will call invokeMethod) returns null.
You could use the Map coercion feature of Groovy to dynamically generate a Map that represents the given interface:
TestInterface getMapAsInterface() {
def map = [:]
TestInterface.class.methods.each() { method ->
map."$method.name" = { Object[] args->
println "Called method ${method.name} with ${args}"
}
}
return map.asType(TestInterface.class)
}
To complete the response of Christoph, as stated by this page, you can implement an interface with a closure. For example:
def map = [doBla: { println 'Bla!'}, hello: {world -> "Hello $world".toString()}] as TestInterface
map.hello 'Groovy' // returns 'Hello Groovy'

Resources