KafkaTemplate.send(key,value,topic) with Custom Partitioner? - spring-kafka

I saw and implemented the method KafkaTemplate.send(TOPIC,message) with default partitioner class.
But here, I am not passing keys. I have a simple custom partitioner class and I also wanna send to kafka server like KafkaTemplate(TOPIC,key,message) where in producerConfig I set my customPartitioner class for partitioning.
I saw this Will send(Topic, Key, Message) method of KafkaTemplate calls Partition method if I provide custom Partitioner? but I didn't get it fully.
my simple customPartitioner class:
public class CustomPartitionar implements Partitioner {
private PartitionMapper newMapper;
public CustomPartitionar(){
newMapper = new PartitionMapper();
}
#Override
public void configure(Map<String, ?> configs) {
}
#Override
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes,Cluster cluster) {
int partition = 0;
String userName = (String) key;
// Find the id of current user based on the username from another mapper class
Integer userId = newMapper.findUserId(userName);
// If the userId not found, default partition is 0
if (userId != null) {
partition = userId;
}
return partition;
}
#Override
public void close() {
}
}
added this class to producerFactory:
config.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, CustomPartitionar.class);
actually my key will be get from "message.getReceiver()" and topic will be get from "message.getTopic()" so my messages will go to desired topic and partition belongs to that user/group..so I just wanna send like:
KafkaTemplate.send(message.getTopic(),message.getReceiver(),message)
can this be possible in a simple way or am I missing something?

The KafkaTemplate has several send methods:
/**
* Send the data to the default topic with no key or partition.
* #param data The data.
* #return a Future for the {#link SendResult}.
*/
ListenableFuture<SendResult<K, V>> sendDefault(V data);
/**
* Send the data to the default topic with the provided key and no partition.
* #param key the key.
* #param data The data.
* #return a Future for the {#link SendResult}.
*/
ListenableFuture<SendResult<K, V>> sendDefault(K key, V data);
/**
* Send the data to the default topic with the provided key and partition.
* #param partition the partition.
* #param key the key.
* #param data the data.
* #return a Future for the {#link SendResult}.
*/
ListenableFuture<SendResult<K, V>> sendDefault(Integer partition, K key, V data);
/**
* Send the data to the default topic with the provided key and partition.
* #param partition the partition.
* #param timestamp the timestamp of the record.
* #param key the key.
* #param data the data.
* #return a Future for the {#link SendResult}.
* #since 1.3
*/
ListenableFuture<SendResult<K, V>> sendDefault(Integer partition, Long timestamp, K key, V data);
/**
* Send the data to the provided topic with no key or partition.
* #param topic the topic.
* #param data The data.
* #return a Future for the {#link SendResult}.
*/
ListenableFuture<SendResult<K, V>> send(String topic, V data);
/**
* Send the data to the provided topic with the provided key and no partition.
* #param topic the topic.
* #param key the key.
* #param data The data.
* #return a Future for the {#link SendResult}.
*/
ListenableFuture<SendResult<K, V>> send(String topic, K key, V data);
/**
* Send the data to the provided topic with the provided key and partition.
* #param topic the topic.
* #param partition the partition.
* #param key the key.
* #param data the data.
* #return a Future for the {#link SendResult}.
*/
ListenableFuture<SendResult<K, V>> send(String topic, Integer partition, K key, V data);
/**
* Send the data to the provided topic with the provided key and partition.
* #param topic the topic.
* #param partition the partition.
* #param timestamp the timestamp of the record.
* #param key the key.
* #param data the data.
* #return a Future for the {#link SendResult}.
* #since 1.3
*/
ListenableFuture<SendResult<K, V>> send(String topic, Integer partition, Long timestamp, K key, V data);
/**
* Send the provided {#link ProducerRecord}.
* #param record the record.
* #return a Future for the {#link SendResult}.
* #since 1.3
*/
ListenableFuture<SendResult<K, V>> send(ProducerRecord<K, V> record);
/**
* Send a message with routing information in message headers. The message payload
* may be converted before sending.
* #param message the message to send.
* #return a Future for the {#link SendResult}.
* #see org.springframework.kafka.support.KafkaHeaders#TOPIC
* #see org.springframework.kafka.support.KafkaHeaders#PARTITION_ID
* #see org.springframework.kafka.support.KafkaHeaders#MESSAGE_KEY
*/
ListenableFuture<SendResult<K, V>> send(Message<?> message);

Related

Is there a way to specify the value of a foreign key without any reference to the entity object or repositories in Doctrine

I have 2 Entities.
Part and Inventory
class Part
{
/**
* #ORM\Id
* #ORM\Column(type="string")
*/
private $partNumber;
/** #ORM\Column(name="part_name", type="string") */
private $partName;
/** #ORM\Column(type="string") */
private $warehouseStatus;
....
Inventory.php
class Inventory
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* One Product has One Shipment.
* #ORM\OneToOne(targetEntity="Part")
* #ORM\JoinColumn(name="part_number", referencedColumnName="part_number")
*/
private $partNumber;
/** #ORM\Column(type="decimal") */
private $inStock;
I create the Part in this way
class one {
private function method1 {
$part = new Part();
$part->partNumber = 'blabla';
$part->warehouseStatus = 1;
.....
}
class two {
private function method1 {
$inv = new Inventory();
$inv->partNumber = 'blabla'; // it crashes here
$inv->inStock = 1;
.....
}
}
In class two I'm trying to make a relation with the first object but partNumber crashes since he is expecting an Entity Object as Part and not a string. Is there an integrated doctrine method to create a reference to the part entity without having to instantiate repositories and so forth.
You need to use the getReference function from the EntityManager for that:
/**
* Gets a reference to the entity identified by the given type and identifier
* without actually loading it, if the entity is not yet loaded.
*
* #param string $entityName The name of the entity type.
* #param mixed $id The entity identifier.
*
* #return object|null The entity reference.
*
* #throws ORMException
*/
public function getReference($entityName, $id);
In your case:
$inv->partNumber = $entityManager->getReference(Part::class, $thePartIdYouReference);

Mass Assignment: Insecure Binder Configuration (Fortify Error) after adding #JsonProperty Annotation

I am getting Mass Assignment: Insecure Binder Configuration in fortify analysis.
Here is the AuthorisationController.class
#Controller
public class AuthorisationController {
#RequestMapping(value = "/authorisation_request", method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<AuthorisationRequest> createAuthorisation(HttpServletRequest request,
#RequestBody AuthorisationRequestInfo createAuthorisation) {
//processing code
}
}
Here is the AuthorisationRequestInfo.class on which the http request params will be mapped.
import com.fasterxml.jackson.annotation.JsonProperty;
public class OrderAuthorisationRequestInfo {
private String hashValue;
private String expiryDateTime;
private Integer initiatingRolePlayerId;
#JsonProperty("feedbackURI")
private String feedbackUri;
/**
* Gets the hash value.
*
* #return the hash value
*/
public String getHashValue() {
return hashValue;
}
/**
* Sets the hash value.
*
* #param hashValue the new hash value
*/
public void setHashValue(String hashValue) {
this.hashValue = hashValue;
}
/**
* Gets the expiry date time.
*
* #return the expiry date time
*/
public String getExpiryDateTime() {
return expiryDateTime;
}
/**
* Sets the expiry date time.
*
* #param expiryDateTime the new expiry date time
*/
public void setExpiryDateTime(String expiryDateTime) {
this.expiryDateTime = expiryDateTime;
}
/**
* Gets the initiating role player id.
*
* #return the initiating role player id
*/
public Integer getInitiatingRolePlayerId() {
return initiatingRolePlayerId;
}
/**
* Sets the initiating role player id.
*
* #param initiatingRolePlayerId the new initiating role player id
*/
public void setInitiatingRolePlayerId(Integer initiatingRolePlayerId) {
this.initiatingRolePlayerId = initiatingRolePlayerId;
}
/**
* Gets the feedback URI.
*
* #return the feedback URI
*/
public String getFeedbackUri() {
return feedbackUri;
}
/**
* Sets the feedback URI.
*
* #param feedbackUri the new feedback URI
*/
public void setFeedbackUri(String feedbackUri) {
this.feedbackUri = feedbackUri;
}
}
The interesting thing is that I only started getting this error after adding the #JsonProperty("feedbackURI") annotation on the feedbackUri column.
#InitBinder was not being used before and there was no fortify error and all the parameters in the request are mandatory.
All other APIs are fine and do not report any fortify issues. Only this api and another one in which the #JsonProperty was added have started showing this error.
Any help would be appreciated.
You can use #JsonIgnoreProperties in your case:
#JsonIgnoreProperties(ignoreUnknown = true)
public class OrderAuthorisationRequestInfo {

Cascading simple derived identity in Doctrine

How can I cascade a joined model with a OneToOne relationship where by only the User table has an auto increment strategy and the joined Profile model must have an id that matches the User id.
My models look like this:
Company\Model\User:
class User
{
/**
* #Id
* #GeneratedValue
* #Column(type="integer")
* #var int
*/
private $id;
/**
* #OneToOne(targetEntity="Profile", inversedBy="user", cascade={"persist"})
* #var Profile
*/
private $profile;
Company\Model\Profile:
class Profile
{
/**
* #Id
* #OneToOne(targetEntity="User", mappedBy="profile")
* #JoinColumn(name="id")
* #var User
*/
private $user;
When persisting an instance of the User model, it causes the following error to be output:
Entity of type Company\Model\Profile is missing an assigned ID for field 'profile'. The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called. If you want automatically generated identifiers instead you need to adjust the metadata mapping accordingly.
The doctrine documentation calls this a simple derived identity, but does not explain how to cascade it.
https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/tutorials/composite-primary-keys.html#use-case-2-simple-derived-identity
It turns out that the answer is actually quite simple.
First the mappedBy and inversedBy need to be swapped around.
Secondly, when setting the Profile on the User you must set the user on the profile in turn.
Company\Model\User:
class User
{
/**
* #Id
* #GeneratedValue
* #Column(type="integer")
* #var int
*/
private $id;
/**
* #OneToOne(targetEntity="Profile", mappedBy="user", cascade={"persist"})
* #var Profile
*/
private $profile;
public function setProfile(Profile $profile): void
{
$this->profile = $profile;
$this->profile->setUser($this);
}
Company\Model\Profile:
class Profile
{
/**
* #Id
* #OneToOne(targetEntity="User", inversedBy="profile")
* #JoinColumn(name="id")
* #var User
*/
private $user;

how to deserialize a POST body content into an Entity with #ExclusionPolicy("all") set

I'm using JMSSerializerBundle and FOSRestBundle and I'm trying to deserialize my body request by means of the #ParamConverter annotation:
/**
* #View()
*
* #Route("/users/{username}/globaltoken", defaults={"_format" = "json"}, requirements={"user"="\w+"})
* #ParamConverter(
* "userBody", class="Belka\AuthBundle\Entity\User",
* converter="fos_rest.request_body"
* )
*/
public function postAction($username, User $userBody)
{
...
The User entity has #ExclusionPolicy("all") set and some attributes are #exposed. That's perfect when I serialize; unfortunatly, when it comes to deserializing my body into a User object the unexposed attribtues are not set. Is there a clean way to handle this?
Answering myself: #ExclusionPolicy(“all”) is not what you want for security purposes. That tag was born for handling data that should not be serialized, whether or not sometimes it should not appear for security reasons. It's a static thing and it's OK like that.
What I really wanted is managing what to show or not (or consider for deserialization) by using groups. Hence:
Declare some groups and assign on the attributes
Use the desired groups in the controller: the deserialization and serialization will consider only the attributes belonging to at least one group declared.
An example:
* Entity *
class User implements EncoderAwareInterface
{
/**
* #ORM\Id
* #ORM\Column(type="string")
* #Assert\NotBlank(message = "user.username.not_blank")
* #ORM\GeneratedValue(strategy="NONE")
* #Serializer\Groups({"default"})
*/
private $username;
/**
* #ORM\Column(type="string", nullable=true)
* #Serializer\Groups("personal")
*/
private $password;
...
* Controller *
/**
* #ParamConverter(
* "userBody",
* class="Belka\AuthBundle\Entity\User",
* converter="fos_rest.request_body",
* options={"deserializationContext"={"groups"={"personal"}}}
* )
*/
public function postAction($username, User $userBody, $_format)
{
that way, only password will be deserialized.

ManyToMany relationship with extra fields in symfony2 orm doctrine

Hi i have that same question as here: Many-to-many self relation with extra fields? but i cant find an answer :/ I tried first ManyToOne and at the other site OneToMany ... but then i could not use something like
public function hasFriend(User $user)
{
return $this->myFriends->contains($user);
}
because there was some this problem:
This function is called, taking a User type $user variable and you then use the contains() function on $this->myFriends.
$this->myFriends is an ArrayCollection of Requests (so different type than User) and from the doctrine documentation about contains():
The comparison of two elements is strict, that means not only the value but also the type must match.
So what is the best way to solve this ManyToMany relationship with extra fields? Or if i would go back and set the onetomany and manytoone relationship how can i modify the hasFriend method? To example check if ID is in array collection of ID's.
EDIT: i have this table... and what i need is:
1. select my friends... and my followers ...check if i am friend with him or not. (because he can be friend with me and i dont have to be with him... like on twitter). I could make manytomany but i need extra fields like: "viewed" "time when he subscribe me" as you can see at my table.
And make query like this and then be able in twig check if (app.user.hasFriend(follower) or something like that)
$qb = $this->createQueryBuilder('r')
->select('u')
->innerJoin('UserBundle:User', 'u')
->Where('r.friend_id=:id')
->setParameter('id', $id)
->orderBy('r.time', 'DESC')
->setMaxResults(50);
return $qb->getQuery()
->getResult();
I was trying to have a many to many relationship with extra fields, and couldn't make it work either... The thing I read in a forum (can't remember where) was:
If you add data to a relationship, then it's not a relationship anymore. It's a new entity.
And it's the right thing to do. Create a new entity with the new fields, and if you need it, create a custom repository to add the methods you need.
A <--- Many to many with field ---> B
would become
A --One to many--> C (with new fields) <-- One to many--B
and of course, C has ManyToOne relationships with both A and B.
I searched everywhere on how to do this, but in the end, it's the right thing to do, if you add data, it's no longer a relationship.
You can also copy what contains usually do, or try to overwrite it in a custom repository, to do whatever you need it to do.
I hope this helps.
I'm adding another answer since it has nothing to do with my original answer. Using the new info you posted, I'm calling the table/entity you posted "Follower". The original entity, "User".
What happens if you create the following associations:
namespace Acme\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\UserBundle\Entity\User
*
* #ORM\Table()
* #ORM\Entity
*/
class User
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Acme\FollowerBundle\Entity\Follower", mappedBy="followeduser")
*/
protected $followers;
/**
* #ORM\OneToMany(targetEntity="Acme\FollowerBundle\Entity\Follower", mappedBy="followeeuser")
*/
protected $followees;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function __construct()
{
$this->followers = new \Doctrine\Common\Collections\ArrayCollection();
$this->followees = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add followers
*
* #param Acme\FollowerBundle\Entity\Follower $follower
*/
public function addFollower(\Acme\FollowerBundle\Entity\Follower $follower)
{
$this->followers[] = $follower;
}
/**
* Add followees
*
* #param Acme\FollowerBundle\Entity\Follower $followee
*/
public function addFollowee(\Acme\FollowerBundle\Entity\Follower $followee)
{
$this->followees[] = $followee;
}
/**
* Get followers
*
* #return Doctrine\Common\Collections\Collection
*/
public function getFollowers()
{
return $this->followers;
}
/**
* Get followees
*
* #return Doctrine\Common\Collections\Collection
*/
public function getFollowees()
{
return $this->followees;
}
}
namespace Acme\FollowerBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\FollowerBundle\Entity\Follower
*
* #ORM\Table()
* #ORM\Entity
*/
class Follower
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User", inversedBy="followers")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $followeduser;
/**
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User", inversedBy="followees")
* #ORM\JoinColumn(name="followee_id", referencedColumnName="id")
*/
protected $followeeuser;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set followeduser
*
* #param Acme\UserBundle\Entity\User $followeduser
*/
public function setFolloweduser(\Acme\UserBundle\Entity\User $followeduser)
{
$this->followeduser = $followeduser;
}
/**
* Get followeduser
*
* #return Acme\UserBundle\Entity\User
*/
public function getFolloweduser()
{
return $this->followeduser;
}
/**
* Set followeeuser
*
* #param Acme\UserBundle\Entity\User $followeeuser
*/
public function setFolloweeuser(\Acme\UserBundle\Entity\User $followeeuser)
{
$this->followeeuser = $followeeuser;
}
/**
* Get followeeuser
*
* #return Acme\UserBundle\Entity\User
*/
public function getFolloweeuser()
{
return $this->followeeuser;
}
}
I'm not sure if this would do the trick, I really don't have much time to test it, but if it doesn't, I thnk that it's on it's way. I'm using two relations, because you don't need a many to many. You need to reference that a user can have a lot of followers, and a follower can follow a lot of users, but since the "user" table is the same one, I did two relations, they have nothing to do with eachother, they just reference the same entity but for different things.
Try that and experiment what happens. You should be able to do things like:
$user->getFollowers();
$follower->getFollowedUser();
and you could then check if a user is being followed by a follower whose user_id equals $userThatIwantToCheck
and you could search in Followers for a Follower whose user = $user and followeduser=$possibleFriend

Resources