Seems since spring-amqp version 1.5, there is a new annotation #queuebinding。But how to use it, i don't know if it can be used on a class or a method? Does it exist any example?
Not sure what problem you have, but here is a sample exactly from the Reference Manual:
#Component
public class MyService {
#RabbitListener(bindings = #QueueBinding(
value = #Queue(value = "myQueue", durable = "true"),
exchange = #Exchange(value = "auto.exch"),
key = "orderRoutingKey")
)
public void processOrder(String data) {
...
}
And yes, it can be use as on class level as well as on method level.
Related
I want to use chronicle queue to store messages using the high level API as mentioned in the answer of this question. But I also want some kind of key for my messages as mentioned here
1.) Firstly , is this the right/efficient way to read/write using high level API? - Code samples below
2.) How do I separate different category of messages? For example "get me all messages for a particular key , the key in code sample below being ric". Maybe use different topics in the same queue? But how would I do that?
Here's my test code to write to the queue:
public void saveHighLevel(MyInterface obj)
{
try (ChronicleQueue queue = ChronicleQueue.singleBuilder(_location).build()) {
ExcerptAppender appender = queue.acquireAppender();
MyInterface trade = appender.methodWriter(MyInterface.class);
// Write
trade.populate(obj);
}
}
And here's one to read:
public void readHighLevel()
{
try(ChronicleQueue queue = ChronicleQueue.singleBuilder(_location).build()) {
ExcerptTailer tailer = queue.createTailer();
MyInterface container = new MyData();
MethodReader reader = tailer.methodReader(container);
while (reader.readOne()) {
System.out.println(container);
}
}
}
MyInterface:
public interface MyInterface
{
public double getPrice();
public int getSize();
public String getRic();
public void populate(MyInterface obj);
}
Implementation of populate:
public void populate(MyInterface obj)
{
this.price = obj.getPrice();
this.ric = obj.getRic();
this.size = obj.getSize();
}
I found the answer for part (2) of my question in the question of this post.
Essentially by doing:
ChronicleQueue queue = ChronicleQueue.singleBuilder("Topic/SubTopic").build();
where Topic can be substituted with the key I'm looking for.
I am using #RabbitListner annotation to recieve messages from a RabbitMq queue.
Although I have done all steps required to do this (i.e. Add #EnableRabbit annotation in my config class) and declare SimpleRabbitListenerContainerFactory as a bean , still my method is not recieving messages from the queue . Can anybody suggest what I am missing :
I am using Spring Boot to launch my application
My launch class
#Configuration
#EnableAutoConfiguration
#EnableRabbit
#EnableConfigurationProperties
#EntityScan("persistence.mysql.domain")
#EnableJpaRepositories("persistence.mysql.dao")
#ComponentScan(excludeFilters = { #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ApiAuthenticationFilter.class),#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ApiVersionValidationFilter.class)},basePackages = {"common", "mqclient","apache", "dispatcher" })
public class Application {
public static void main(final String[] args) {
final SpringApplicationBuilder appBuilder = new SpringApplicationBuilder(
Application.class);
appBuilder.application().setWebEnvironment(false);
appBuilder.profiles("common", "common_mysql_db", "common_rabbitmq")
.run(args);
}
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
}
Here is my Bean to define SimpleRabbitListenerContainerFactory inside a component class
#Component(value = "inputQueueManager")
public class InputQueueManagerImpl extends AbstractQueueManagerImpl {
..///..
#Bean(name = "inputListenerContainerFactory")
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory()
{
SimpleRabbitListenerContainerFactory factory = new
SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(this.rabbitConnectionFactory);
factory.setConcurrentConsumers(Integer.parseInt(this.concurrentConsumers));
factory.setMaxConcurrentConsumers(Integer.parseInt(this.maxConcurrentConsumers));
factory.setMessageConverter(new Jackson2JsonMessageConverter());
return factory;
}
}
And finally my Listener inside another Controller component
#Controller
public class RabbitListner{
#RabbitListener(queues = "Storm1", containerFactory = "inputListenerContainerFactory")
#Override
public void processMessage(QueueMessage message) {
String topic = message.getTopic();
String payload = message.getPayload();
dispatcher.bean.EventBean eventBean = new dispatcher.bean.EventBean();
System.out.println("Data read from the queue");
Unfortunately , I am sending the messages to the queue but the code inside processMessage is not getting executed ever.
I am not sure what is the problem here . Can anybody help ??
By default, the Json message converter requires hints in the message properties as to what type of object to create.
If your producer does not set those properties, it won't be able to do the conversion without some help.
You can inject a ClassMapper into the converter.
The framework provides a DefaultClassMapper which can be customized - either to look at a different message property than the default __TypeId__ property.
If you always want to convert the json to the same object, you can simply set the default type:
DefaultClassMapper classMapper = newDefaultClassMapper();
classMapper.setDefaultType(QueueMessage.class);
Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter();
converter.setClassMapper(classMapper);
factory.setMessageConverter(new Jackson2JsonMessageConverter());
The documentation already shows how to configure this.
I am new to broadleaf. I want to create a custom customerEndPoint Class which will provide services like registering customer getting a customer details etc. I tried creating a CustomerEndpoint Class in com.mycompany.api.endpoint.customer package. Is there any other configurations to be done to access the customer urls??
Please help on this...
I solved this, Sharing it as it may be helpful for someone.
I Configured the CustomerEndPoint bean in applicationContent-rest-api.xml and annotated CustomerEndpoint as controller and just extented the BaseEndPoint.
CustomerEndpoint.java
#Controller
#Scope("singleton")
#Path("/customer/")
#Produces(value = { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
#Consumes(value = { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public class CustomerEndpoint extends BaseEndpoint {
#Resource(name = "blCustomerService")
protected CustomerService customerService;
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
#GET
public CustomerWrapper getCustomer(#Context HttpServletRequest request,
#QueryParam("id") String emailId) {
CustomerWrapper customerWrapper = new CustomerWrapper();
if (emailId != null && emailId != "") {
customerWrapper.wrapDetails(
customerService.readCustomerByEmail(emailId), request);
}
return customerWrapper;
}
}
applicationContext-rest-api.xml
<bean id="customerEndpoint" class="com.mycompany.api.endpoint.customer.CustomerEndpoint"/>
It depends of whatever version are you using. If you using for example : broadleaf-3.1.X see
http://mvnrepository.com/artifact/org.broadleafcommerce/broadleaf-framework/3.1.5-GA
You could take as an example com.mycompany.api.endpoint.checkout.CheckoutEndpoint.
Into default platform there is org.broadleafcommerce.core.web.api.endpoint.customer.CustomerEndpoint but this implementation is empty.
You could extend that class and add annotation similar to com.mycompany.api.endpoint.checkout.CheckoutEndpoint also add business logic according to your needs.
There isn't some platform default implementation into platform as far as I can see int broadleaf-3.1.6-GA
I am trying to serialize a HashMap from Objects to Strings, but the specific Object has a reference to the current class leading to an infinite recursion, which doesn't seem to be solved with the usual JsonIdentifyInfo annotation. Here's an example:
public class CircularKey {
public void start() throws IOException {
ObjectMapper mapper = new ObjectMapper();
Cat cat = new Cat();
// Encode
String json = mapper.writeValueAsString(cat);
System.out.println(json);
// Decode
Cat cat2 = mapper.readValue(json, Cat.class);
System.out.println(mapper.writeValueAsString(cat2));
}
}
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "#id")
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#class")
class Mouse {
int id;
#JsonProperty
Cat cat;
}
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "#id")
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#class")
class Cat {
int id;
#JsonSerialize(keyUsing = MouseMapKeySerializer.class)
#JsonDeserialize(keyUsing = MouseMapKeyDeserializer.class)
#JsonProperty
HashMap<Mouse, String> status = new HashMap<Mouse, String>();
public Cat() {
Mouse m = new Mouse();
m.cat = this;
status.put(m, "mike");
}
}
Here's the serializer/deserializer for the key:
class MouseMapKeySerializer extends JsonSerializer<Mouse> {
static ObjectMapper mapper = new ObjectMapper();
#Override
public void serialize(Mouse value, JsonGenerator generator,
SerializerProvider provider) throws IOException,
JsonProcessingException {
String json = mapper.writeValueAsString(value);
generator.writeFieldName(json);
}
}
class MouseMapKeyDeserializer extends KeyDeserializer {
static ObjectMapper mapper = new ObjectMapper();
#Override
public Mouse deserializeKey(String c, DeserializationContext ctx)
throws IOException, JsonProcessingException {
return mapper.readValue(c, Mouse.class);
}
}
If I switch the map to HashMap (String,Object) it works but I cannot change the original mapping. Any ideas?
It looks like you found your answer at http://jackson-users.ning.com/forum/topics/serializing-hashmap-with-object-key-and-recursion. This doesn't seem to be possible because:
Complex keys are tricky, and it is not a use case I ever considered. Then again, there is nothing specifically preventing use of standard components; main concern was just the limitations than JSON has (must be String-value, JsonParser/JsonGenerator expose keys as different tokens).
There is no explicit support for either polymorphic types or object ids for Object keys. Standard serializers/deserializers are mostly for relatively simple types that can be easily and reliably converted to/from Strings; numbers, Dates, UUIDs.
So: unlike with value handlers, where modular design (with separation of TypeSerializer/JsonSerializer) makes sense, I think what you need to do is to have custom (de)serializers that handle all aspects. You should be able to use code from existing value (de)serializers, type (de)serializers, but not classes themselves.
Your use case does sound interesting, but for better or worse, it is pushing the envelope quite a bit. :-)
How do I do constructor injection when I'm manually initializing the class?
public class ApiKeyHandler : DelegatingHandler
{
private IApiService apiService;
public ApiKeyHandler(IApiService apiService)
{
this.apiService = apiService;
}
}
Initializing:
var apiKey = new ApiKeyHandler(/*inject here */);
How do I accomplish this? My bindings and everything is already setup.
You want to do something like this:
var apiKey = new ApiKeyHandler(kernel.Get<IApiService>());
However, why not inject the ApiKeyHandler itself?
var apiKey = kernel.Get<ApiKeyHandler>();
Here is an article about Ninject:
You basically want to set this up at the beginning of your code and have it available globally:
public IKernel kernel = new StandardKernel();
...
kernel.Bind<IApiService>()
.To<SomeConcreteApiService>();