4242import org .prebid .server .proto .openrtb .ext .request .pubmatic .ExtImpPubmaticKeyVal ;
4343import org .prebid .server .proto .openrtb .ext .response .BidType ;
4444import org .prebid .server .proto .openrtb .ext .response .ExtBidPrebid ;
45+ import org .prebid .server .proto .openrtb .ext .response .ExtBidPrebidMeta ;
4546import org .prebid .server .proto .openrtb .ext .response .ExtBidPrebidVideo ;
4647import org .prebid .server .proto .openrtb .ext .response .ExtIgi ;
4748import org .prebid .server .proto .openrtb .ext .response .ExtIgiIgs ;
@@ -504,6 +505,7 @@ public CompositeBidderResponse makeBidderResponse(BidderCall<BidRequest> httpCal
504505 return CompositeBidderResponse .builder ()
505506 .bids (extractBids (bidResponse , errors ))
506507 .igi (extractIgi (bidResponse ))
508+ .errors (errors )
507509 .build ();
508510 } catch (DecodeException | PreBidException e ) {
509511 return CompositeBidderResponse .withError (BidderError .badServerResponse (e .getMessage ()));
@@ -516,13 +518,67 @@ private List<BidderBid> extractBids(PubmaticBidResponse bidResponse, List<Bidder
516518 : bidsFromResponse (bidResponse , bidderErrors );
517519 }
518520
521+ private static BidType getBidType (Bid bid , List <BidderError > errors ) {
522+ return switch (bid .getMtype ()) {
523+ case 1 -> BidType .banner ;
524+ case 2 -> BidType .video ;
525+ case 3 -> BidType .audio ;
526+ case 4 -> BidType .xNative ;
527+ case null , default -> {
528+ errors .add (BidderError .badServerResponse ("failed to parse bid mtype (%d) for impression id %s"
529+ .formatted (bid .getMtype (), bid .getImpid ())));
530+ yield null ;
531+ }
532+ };
533+ }
534+
535+ private static Integer getDuration (PubmaticBidExt bidExt ) {
536+ return Optional .ofNullable (bidExt )
537+ .map (PubmaticBidExt ::getVideo )
538+ .map (VideoCreativeInfo ::getDuration )
539+ .orElse (null );
540+ }
541+
542+ private PubmaticBidExt parseBidExt (ObjectNode bidExt , List <BidderError > errors ) {
543+ try {
544+ return bidExt != null ? mapper .mapper ().treeToValue (bidExt , PubmaticBidExt .class ) : null ;
545+ } catch (JsonProcessingException e ) {
546+ errors .add (BidderError .badServerResponse (e .getMessage ()));
547+ return null ;
548+ }
549+ }
550+
551+ private static boolean getInBannerVideo (PubmaticBidExt bidExt ) {
552+ return Optional .ofNullable (bidExt )
553+ .map (PubmaticBidExt ::getInBannerVideo )
554+ .orElse (false );
555+ }
556+
557+ private String resolveNativeAdm (String adm , List <BidderError > bidderErrors ) {
558+ final JsonNode admNode ;
559+ try {
560+ admNode = mapper .mapper ().readTree (adm );
561+ } catch (JsonProcessingException e ) {
562+ bidderErrors .add (BidderError .badServerResponse ("Unable to parse native adm: %s" .formatted (adm )));
563+ return null ;
564+ }
565+
566+ final JsonNode nativeNode = admNode .get ("native" );
567+ if (nativeNode != null && !nativeNode .isMissingNode ()) {
568+ return nativeNode .toString ();
569+ }
570+
571+ return null ;
572+ }
573+
519574 private List <BidderBid > bidsFromResponse (PubmaticBidResponse bidResponse , List <BidderError > bidderErrors ) {
520575 return bidResponse .getSeatbid ().stream ()
521576 .filter (Objects ::nonNull )
522577 .map (SeatBid ::getBid )
523578 .filter (Objects ::nonNull )
524579 .flatMap (Collection ::stream )
525580 .map (bid -> resolveBidderBid (bid , bidResponse .getCur (), bidderErrors ))
581+ .filter (Objects ::nonNull )
526582 .toList ();
527583 }
528584
@@ -533,21 +589,22 @@ private BidderBid resolveBidderBid(Bid bid, String currency, List<BidderError> b
533589 : null ;
534590
535591 final PubmaticBidExt pubmaticBidExt = parseBidExt (bid .getExt (), bidderErrors );
536- final Integer duration = getDuration (pubmaticBidExt );
537- final BidType bidType = getBidType (pubmaticBidExt );
592+ final BidType bidType = getBidType (bid , bidderErrors );
593+
594+ if (bidType == null ) {
595+ return null ;
596+ }
538597
539598 final String bidAdm = bid .getAdm ();
540599 final String resolvedAdm = bidAdm != null && bidType == BidType .xNative
541600 ? resolveNativeAdm (bidAdm , bidderErrors )
542601 : bidAdm ;
543602
544- final Bid updatedBid = firstCat != null || duration != null || resolvedAdm != null
545- ? bid .toBuilder ()
603+ final Bid updatedBid = bid .toBuilder ()
546604 .cat (firstCat )
547605 .adm (resolvedAdm != null ? resolvedAdm : bidAdm )
548- .ext (duration != null ? updateBidExtWithExtPrebid (duration , bid .getExt ()) : bid .getExt ())
549- .build ()
550- : bid ;
606+ .ext (updateBidExtWithExtPrebid (pubmaticBidExt , bidType , bid .getExt ()))
607+ .build ();
551608
552609 return BidderBid .builder ()
553610 .bid (updatedBid )
@@ -558,54 +615,20 @@ private BidderBid resolveBidderBid(Bid bid, String currency, List<BidderError> b
558615 .build ();
559616 }
560617
561- private PubmaticBidExt parseBidExt (ObjectNode bidExt , List <BidderError > errors ) {
562- try {
563- return bidExt != null ? mapper .mapper ().treeToValue (bidExt , PubmaticBidExt .class ) : null ;
564- } catch (JsonProcessingException e ) {
565- errors .add (BidderError .badServerResponse (e .getMessage ()));
566- return null ;
567- }
568- }
569-
570- private static Integer getDuration (PubmaticBidExt bidExt ) {
571- return Optional .ofNullable (bidExt )
572- .map (PubmaticBidExt ::getVideo )
573- .map (VideoCreativeInfo ::getDuration )
574- .orElse (null );
575- }
576-
577- private static BidType getBidType (PubmaticBidExt bidExt ) {
578- final int bidType = Optional .ofNullable (bidExt )
579- .map (PubmaticBidExt ::getBidType )
580- .orElse (0 );
581-
582- return switch (bidType ) {
583- case 1 -> BidType .video ;
584- case 2 -> BidType .xNative ;
585- default -> BidType .banner ;
586- };
587- }
588-
589- private String resolveNativeAdm (String adm , List <BidderError > bidderErrors ) {
590- final JsonNode admNode ;
591- try {
592- admNode = mapper .mapper ().readTree (adm );
593- } catch (JsonProcessingException e ) {
594- bidderErrors .add (BidderError .badServerResponse ("Unable to parse native adm: %s" .formatted (adm )));
595- return null ;
596- }
597-
598- final JsonNode nativeNode = admNode .get ("native" );
599- if (nativeNode != null && !nativeNode .isMissingNode ()) {
600- return nativeNode .toString ();
601- }
618+ private ObjectNode updateBidExtWithExtPrebid (PubmaticBidExt pubmaticBidExt , BidType type , ObjectNode extBid ) {
619+ final Integer duration = getDuration (pubmaticBidExt );
620+ final boolean inBannerVideo = getInBannerVideo (pubmaticBidExt );
602621
603- return null ;
604- }
622+ final ExtBidPrebid extBidPrebid = ExtBidPrebid .builder ()
623+ .video (duration != null ? ExtBidPrebidVideo .of (duration , null ) : null )
624+ .meta (ExtBidPrebidMeta .builder ()
625+ .mediaType (inBannerVideo ? BidType .video .getName () : type .getName ())
626+ .build ())
627+ .build ();
605628
606- private ObjectNode updateBidExtWithExtPrebid ( Integer duration , ObjectNode extBid ) {
607- final ExtBidPrebid extBidPrebid = ExtBidPrebid . builder (). video ( ExtBidPrebidVideo . of ( duration , null )). build ();
608- return extBid .set (PREBID , mapper .mapper ().valueToTree (extBidPrebid ));
629+ return extBid != null
630+ ? extBid . set ( PREBID , mapper . mapper (). valueToTree ( extBidPrebid ))
631+ : mapper . mapper (). createObjectNode () .set (PREBID , mapper .mapper ().valueToTree (extBidPrebid ));
609632 }
610633
611634 private static Integer getDealPriority (PubmaticBidExt bidExt ) {
0 commit comments