--- a/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
+++ b/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
@@ -27,17 +_,36 @@
         ServerLevel serverLevel = blockSource.level();
         Direction direction = blockSource.state().getValue(DispenserBlock.FACING);
         Position dispensePosition = this.dispenseConfig.positionFunction().getDispensePosition(blockSource, direction);
-        Projectile.spawnProjectileUsingShoot(
-            this.projectileItem.asProjectile(serverLevel, dispensePosition, item, direction),
-            serverLevel,
-            item,
-            direction.getStepX(),
-            direction.getStepY(),
-            direction.getStepZ(),
-            this.dispenseConfig.power(),
-            this.dispenseConfig.uncertainty()
-        );
-        item.shrink(1);
+        ItemStack singleItemStack = item.copyWithCount(1); // Paper - shrink below and single item in event
+        org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
+        org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
+
+        org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(direction.getStepX(), direction.getStepY(), direction.getStepZ()));
+        serverLevel.getCraftServer().getPluginManager().callEvent(event);
+
+        if (event.isCancelled()) {
+            return item;
+        }
+
+        boolean shrink = true;
+        if (!event.getItem().equals(craftItem)) {
+            shrink = false;
+            // Chain to handler for new item
+            ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+            DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+            if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+                dispenseBehavior.dispense(blockSource, eventStack);
+                return item;
+            }
+        }
+
+        // SPIGOT-7923: Avoid create projectiles with empty item
+        if (!singleItemStack.isEmpty()) {
+            Projectile projectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(serverLevel, dispensePosition, org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()), direction), serverLevel, singleItemStack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); // Paper - track changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies
+            projectile.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(blockSource.blockEntity());
+        }
+        if (shrink) item.shrink(1);
+        // CraftBukkit end
         return item;
     }
 
